OKhttp攔截器實現(xiàn)實踐環(huán)節(jié)源碼解析
正文
本節(jié)我們開始自我實現(xiàn)我們自己okhttp框架中的每個攔截器。
先簡單回顧一下各個攔截器的作用:
- RetryAndFollowUpInterceptor:重試攔截器
處理重試的一個攔截器,會去處理一些異常,根據(jù)底層返回的響應數(shù)據(jù),先進行一些特殊狀態(tài)碼的判斷,例如:如果底層返回307,則根據(jù)服務端返回的最新location,重新構建新的請求,交由底層攔截器,重新發(fā)起請求。如果底層返回路由異常、某些IO異常,則會continue,重新發(fā)起請求。
- BridgeInterceptor:基礎的攔截器
給我們平常發(fā)起的請求,添加通用和請求首部信息,做一個簡單的處理,設置一些通用的請求頭,Cookie、Connection、Content-Type、Content-Length,做一些返回的處理,如果返回的數(shù)據(jù)被壓縮了,采用 ZipSource,保存Cookie。
- CacheInterceptor:緩存攔截器
緩存存儲策略、緩存過期策略、緩存對比策略的具體實現(xiàn)。
- ConnectInterceptor:連接的攔截器
ConnectInterceptor負責連接復用、建立socket連接,okio與socket輸入輸出流綁定。
- CallServerInterceptor: 具體與服務器通信,給服務器寫數(shù)據(jù)和讀取數(shù)據(jù);
攔截器的自我實現(xiàn)
好了,接下來,把我們之前寫的框架的代碼,重新梳理一下,新增一下幾個攔截器。 RealCall.java
package com.itbird.okhttpstudy.okhttp; import android.util.Log; import com.itbird.okhttpstudy.interceptor.BridgeInterceptor; import com.itbird.okhttpstudy.interceptor.CacheInterceptor; import com.itbird.okhttpstudy.interceptor.CallServerInterceptor; import com.itbird.okhttpstudy.interceptor.ConnectInterceptor; import com.itbird.okhttpstudy.interceptor.Interceptor; import com.itbird.okhttpstudy.interceptor.RetryAndFollowUpInterceptor; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Created by itbird on 2022/11/21 */ public class RealCall implements Call { private Request request; private OkhttpClient okhttpClient; public RealCall(Request request, OkhttpClient okhttpClient) { this.request = request; this.okhttpClient = okhttpClient; } @Override public void enqueue(Callback callback) { okhttpClient.dispatcher().enqueue(new AsyncCall(callback)); } @Override public Response execute() { return getResponseWithInterceptorChain(); } @Override public Request request() { return request; } private Response getResponseWithInterceptorChain() { List<Interceptor> interceptors = new ArrayList<Interceptor>(); interceptors.add(new BridgeInterceptor());// 基礎 interceptors.add(new CacheInterceptor());// 緩存 interceptors.add(new ConnectInterceptor());// 建立連接 interceptors.add(new CallServerInterceptor());// 寫數(shù)據(jù) interceptors.add(new RetryAndFollowUpInterceptor());// 重試 Interceptor.Chain chain = new RealInterceptorChain(this, interceptors, request); try { return chain.proceed(request); } catch (IOException e) { //處理過程被中斷時,通過錯誤碼返回 return null; } } class AsyncCall extends NamedRunnable { private Callback callback; public AsyncCall(Callback callback) { this.callback = callback; } @Override public void execute() { Log.d(Constants.TAG, "AsyncCall execute"); //這里有問題的 Response response = getResponseWithInterceptorChain(); if (callback != null) { try { callback.onResponse(RealCall.this, response); } catch (IOException e) { } } } } }
接下來還是老辦法,按照AS提示,新建這些類。
RetryAndFollowUpInterceptor
package com.itbird.okhttpstudy.interceptor; import android.util.Log; import com.itbird.okhttpstudy.okhttp.Constants; import com.itbird.okhttpstudy.okhttp.Request; import com.itbird.okhttpstudy.okhttp.Response; import java.io.IOException; /** * Created by itbird on 2022/11/24 */ public class RetryAndFollowUpInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Log.d(Constants.TAG, "RetryAndFollowUpInterceptor"); Request request = chain.request(); //okhttp表現(xiàn)為,此處,去根據(jù)底層拋出的異常,決定是否為關鍵錯誤異常,如果不是,則while true循環(huán),去執(zhí)行重試請求 return chain.proceed(request); } }
BridgeInterceptor
package com.itbird.okhttpstudy.interceptor; import android.util.Log; import com.itbird.okhttpstudy.okhttp.Constants; import com.itbird.okhttpstudy.okhttp.Request; import com.itbird.okhttpstudy.okhttp.RequsetBody; import com.itbird.okhttpstudy.okhttp.Response; import java.io.IOException; /** * Created by itbird on 2022/11/24 */ public class BridgeInterceptor implements Interceptor { public BridgeInterceptor() { } @Override public Response intercept(Chain chain) throws IOException { Log.d(Constants.TAG, "BridgeInterceptor"); Request request = chain.request(); // 添加一些請求頭 // request.addParam("Connection", "keep-alive"); // 做一些其他處理 if (request.requsetBody() != null) { RequsetBody requestBody = request.requsetBody(); request.addParam("Content-Type", requestBody.getContentType()); request.addParam("Content-Length", Long.toString(requestBody.getContentLength())); } //GZIP數(shù)據(jù)流轉換 return chain.proceed(request); } }
CacheInterceptor
package com.itbird.okhttpstudy.interceptor; import android.util.Log; import com.itbird.okhttpstudy.okhttp.CacheControl; import com.itbird.okhttpstudy.okhttp.Constants; import com.itbird.okhttpstudy.okhttp.Request; import com.itbird.okhttpstudy.okhttp.Response; import java.io.IOException; /** * Created by itbird on 2022/11/24 */ public class CacheInterceptor implements Interceptor { public CacheInterceptor() { } @Override public Response intercept(Chain chain) throws IOException { Log.d(Constants.TAG, "CacheInterceptor"); Request request = chain.request(); if (request.cache() == CacheControl.FORCE_CACHE) { //本地緩存有沒有,緩存過期了沒有,緩存對比服務器返回307 } return chain.proceed(request); } }
ConnectInterceptor
package com.itbird.okhttpstudy.interceptor; import android.util.Log; import com.itbird.okhttpstudy.okhttp.Constants; import com.itbird.okhttpstudy.okhttp.Request; import com.itbird.okhttpstudy.okhttp.Response; import java.io.IOException; /** * Created by itbird on 2022/11/24 */ public class ConnectInterceptor implements Interceptor { public ConnectInterceptor() { } @Override public Response intercept(Chain chain) throws IOException { Log.d(Constants.TAG, "ConnectInterceptor"); Request request = chain.request(); //表現(xiàn)為okhttp的話,這里就是socket簡歷連接,并且將socket輸入輸出流與okio綁定在一起 return chain.proceed(request); } }
CallServerInterceptor
package com.itbird.okhttpstudy.interceptor; import android.util.Log; import com.itbird.okhttpstudy.okhttp.Constants; import com.itbird.okhttpstudy.okhttp.Request; import com.itbird.okhttpstudy.okhttp.Response; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; /** * Created by itbird on 2022/11/24 */ public class CallServerInterceptor implements Interceptor { public CallServerInterceptor() { } @Override public Response intercept(Chain chain) throws IOException { Log.d(Constants.TAG, "CallServerInterceptor"); Request request = chain.request(); try { //獲取連接請求 URL url = new URL(request.url()); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); //設置連接超時 httpURLConnection.setConnectTimeout(3000); //設置方法 httpURLConnection.setRequestMethod(request.method()); if (request.requsetBody() != null) { httpURLConnection.setRequestProperty("Content-Type", request.requsetBody().getContentType()); httpURLConnection.setRequestProperty("Content-Length", String.valueOf(request.requsetBody().getContentLength())); Log.d(Constants.TAG, httpURLConnection.getRequestProperty("Content-Length")); Log.d(Constants.TAG, httpURLConnection.getRequestProperty("Content-Type")); } //開始連接 httpURLConnection.connect(); //插入,如果requsetbody不為空,則繼續(xù)寫入內容 if (request.requsetBody() != null) { request.requsetBody().writeBodyData(httpURLConnection.getOutputStream()); } //判斷返回的狀態(tài)碼 if (httpURLConnection.getResponseCode() == 200) { //獲取返回的數(shù)據(jù) InputStream inputStream = httpURLConnection.getInputStream(); //將返回的數(shù)據(jù),封裝為response Response response = new Response(inputStream); return response; } } catch (MalformedURLException e) { throw e; } catch (IOException e) { throw e; } return null; } }
運行一下
題外話
說到責任鏈模式,這里有一個題外話,我們之前分析view事件源碼的時候,也看到過,view 事件源碼,也是責任鏈機制,它是通過每層返回true、false來決定是否攔截。
大家想一下,和okhttp這里的責任鏈有啥不同的?我們上面查看okhttp源碼的時候知道,它并不是通過每層返回true or false來決定是否攔截的,而是根據(jù)每層返回的response 以及 是否拋出異常來決定是否攔截。
以上就是OKhttp攔截器實現(xiàn)實踐環(huán)節(jié)源碼解析的詳細內容,更多關于OKhttp 攔截器實現(xiàn)的資料請關注腳本之家其它相關文章!
相關文章
Android 異步任務 設置 超時使用handler更新通知功能
這篇文章主要介紹了Android 異步任務 設置 超時使用handler更新通知,文中給大家提到了使用AsyncTask設置請求超時的注意事項 ,需要的朋友可以參考下2017-12-12Android實現(xiàn)關機后數(shù)據(jù)不會丟失問題
這篇文章主要介紹了Android實現(xiàn)關機后數(shù)據(jù)不會丟失問題,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-10-10android尺子的自定義view——RulerView詳解
這篇文章主要介紹了android尺子的自定義view——RulerView詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03