(一)Interceptor chain
OkHttp 的 Interceptor chain 是比較特色的一個東西。我們通過添加自定義的 Interceptor 可以對請求的前、后做一些額外的攔截處理,然而實際上 OkHttp 框架的核心流程也是通過它實現的,以下是 RealCall 中的 getResponseWithInterceptorChain() 方法:
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
// 用戶自定義的 interceptor
interceptors.addAll(client.interceptors());
// 負責失敗重試以及重定向的
interceptors.add(retryAndFollowUpInterceptor);
/** Bridges from application code to network code.
* First it builds a network request from a user request.
* Then it proceeds to call the network.
* Finally it builds a user response from the network response. */
interceptors.add(new BridgeInterceptor(client.cookieJar()));
/** Serves requests from the cache and writes responses to the cache. */
interceptors.add(new CacheInterceptor(client.internalCache()));
/** Opens a connection to the target server and proceeds to the next interceptor. */
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
/** This is the last interceptor in the chain. It makes a network call to the server. */
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
Interceptor chain 是個 責任鏈模式
它包含了一些命令對象和一系列的處理對象,每一個處理對象決定它能處理哪些命令對象,它也知道如何將它不能處理的命令對象傳遞給該鏈中的下一個處理對象。該模式還描述了往該處理鏈的末尾添加新的處理對象的方法。
Interceptor 便是這樣,它首先實現自己的職責,比如 BridgeInterceptor 首先通過客戶端的 request 創建一個 Request.Builder,然后調用下一個 Interceptor(也就是 CacheInterceptor,可以參考下圖中 Interceptor 的調用順序) 的 proceed 來得到 response,
Response networkResponse = chain.proceed(requestBuilder.build());
最后構建一個新的 Response.Builder 并返回。
OkHttp 流程圖
其實 Interceptor 的設計也是一種分層的思想,每個 Interceptor 就是一層,分層簡化了每一層的邏輯,每層只需要關注自己的責任(單一原則思想也在此體現),而各層之間通過約定的接口/協議進行合作(面向接口編程思想),共同完成復雜的任務。
(二)自定義 Interceptor
- 比如請求中添加統一的 header 和 QueryParameter;
- 沒有網絡的情況下,嘗試使用 cache。
……
private static class RequestInterceptor implements Interceptor {
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request.Builder requestBuilder = chain.request().newBuilder();
requestBuilder.addHeader("os_name", "Android");
……
return chain.proceed(requestBuilder.build());
}
}