網站首頁 編程語言 正文
正文
本節我們開始自我實現我們自己okhttp框架中的每個攔截器。
先簡單回顧一下各個攔截器的作用:
- RetryAndFollowUpInterceptor:重試攔截器
處理重試的一個攔截器,會去處理一些異常,根據底層返回的響應數據,先進行一些特殊狀態碼的判斷,例如:如果底層返回307,則根據服務端返回的最新location,重新構建新的請求,交由底層攔截器,重新發起請求。如果底層返回路由異常、某些IO異常,則會continue,重新發起請求。
- BridgeInterceptor:基礎的攔截器
給我們平常發起的請求,添加通用和請求首部信息,做一個簡單的處理,設置一些通用的請求頭,Cookie、Connection、Content-Type、Content-Length,做一些返回的處理,如果返回的數據被壓縮了,采用 ZipSource,保存Cookie。
- CacheInterceptor:緩存攔截器
緩存存儲策略、緩存過期策略、緩存對比策略的具體實現。
- ConnectInterceptor:連接的攔截器
ConnectInterceptor負責連接復用、建立socket連接,okio與socket輸入輸出流綁定。
- CallServerInterceptor: 具體與服務器通信,給服務器寫數據和讀取數據;
攔截器的自我實現
好了,接下來,把我們之前寫的框架的代碼,重新梳理一下,新增一下幾個攔截器。 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());// 寫數據
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表現為,此處,去根據底層拋出的異常,決定是否為關鍵錯誤異常,如果不是,則while true循環,去執行重試請求
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數據流轉換
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();
//表現為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不為空,則繼續寫入內容
if (request.requsetBody() != null) {
request.requsetBody().writeBodyData(httpURLConnection.getOutputStream());
}
//判斷返回的狀態碼
if (httpURLConnection.getResponseCode() == 200) {
//獲取返回的數據
InputStream inputStream = httpURLConnection.getInputStream();
//將返回的數據,封裝為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來決定是否攔截的,而是根據每層返回的response 以及 是否拋出異常來決定是否攔截。
原文鏈接:https://juejin.cn/post/7181992810667573306
相關推薦
- 2023-03-02 C語言數據結構中約瑟夫環問題探究_C 語言
- 2022-04-30 C語言鏈表實現商品庫存管理系統_C 語言
- 2022-06-02 一篇文章帶你了解Python中的裝飾器_python
- 2022-08-10 C#對文件名智能排序的算法_C#教程
- 2022-11-14 C#中對集合排序的三種方式_C#教程
- 2022-04-11 jackson中對null的處理
- 2022-04-01 k8s集群中移除節點后重新加入
- 2022-07-11 使用?Loki?實現?Kubernetes?容器日志監控的方法_相關技巧
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支