在本系列的上一篇文章中,咱們學習了OkHttp的基本用法,體驗了這個網絡加載框架的強大功能,以及它很是簡便的API。尚未看過上一篇文章的朋友,建議先去閱讀 網絡請求框架OkHttp3全解系列 - (一)OkHttp的基本使用 。java
若是咱們想要進行get請求,那麼使用少許的代碼就能實現,以下所示:web
OkHttpClient httpClient = new OkHttpClient();
String url = "https://www.baidu.com/";
Request getRequest = new Request.Builder()
.url(url)
.get()
.build();
Call call = httpClient.newCall(getRequest);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
複製代碼
看起來很簡潔的代碼,實際是OkHttp在背後幫咱們默默執行了成噸的工做。緩存
知其然也要知其因此然。那麼這篇咱們就來解析一下OkHttp的源碼,看看它在這些簡單用法的背後,到底執行了多麼複雜的工做。安全
以上面get請求的代碼步驟分析,那麼先分析OkHttpClient實例的建立。 在上一篇中,提到OkHttpClient實例化能夠直接建立,也可使用Builder建造者模式進行配置而後build()便可。直接建立其實就是使用了默認的配置。其構造方法以下:cookie
public OkHttpClient() {
this(new Builder());
}
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;//調度器,用於控制併發的請求。內部保存同步和異步請求的call,並使用線程池處理異步請求。
this.proxy = builder.proxy;//代理設置
this.protocols = builder.protocols;//http協議
this.connectionSpecs = builder.connectionSpecs;//鏈接配置
this.interceptors = Util.immutableList(builder.interceptors);//全局攔截器
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);//網絡攔截器
this.eventListenerFactory = builder.eventListenerFactory;//請求的監聽器的建立工廠
this.proxySelector = builder.proxySelector;//代理選擇器
this.cookieJar = builder.cookieJar;//cookie,默認沒有cookie:CookieJar.NO_COOKIES
this.cache = builder.cache;//網絡緩存設置
this.internalCache = builder.internalCache;//內部使用的緩存接口
this.socketFactory = builder.socketFactory;//socket工廠
boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}
if (builder.sslSocketFactory != null || !isTLS) {
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
X509TrustManager trustManager = Util.platformTrustManager();
this.sslSocketFactory = newSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
if (sslSocketFactory != null) {
Platform.get().configureSslSocketFactory(sslSocketFactory);
}
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;//以上幾個是安全相關設置
this.connectionPool = builder.connectionPool;//鏈接池
this.dns = builder.dns;//域名解析系統
this.followSslRedirects = builder.followSslRedirects;//ssl重定向
this.followRedirects = builder.followRedirects;//重定向
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;//鏈接失敗時是否重試
this.callTimeout = builder.callTimeout;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;//幾個超時設置
this.pingInterval = builder.pingInterval;//ping間隔時間
//攔截器不能是null
if (interceptors.contains(null)) {
throw new IllegalStateException("Null interceptor: " + interceptors);
}
if (networkInterceptors.contains(null)) {
throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
}
}
public static final class Builder {
...
public Builder() {
//默認的配置
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
if (proxySelector == null) {
proxySelector = new NullProxySelector();
}
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
callTimeout = 0;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
...
}
複製代碼
直接建立OkHttpClient實例,配置項就是Builder構造方法中默認值。 可見配置項是很是多的,包括上一篇中已經使用過的超時設置、攔截器。網絡
接着看Request的建立,也是使用建造者模式:併發
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
public Builder get() {
return method("GET", null);
}
public Builder post(RequestBody body) {
return method("POST", body);
}
public Builder method(String method, @Nullable RequestBody body) {
if (method == null) throw new NullPointerException("method == null");
if (method.length() == 0) throw new IllegalArgumentException("method.length() == 0");
if (body != null && !HttpMethod.permitsRequestBody(method)) {
throw new IllegalArgumentException("method " + method + " must not have a request body.");
}
if (body == null && HttpMethod.requiresRequestBody(method)) {
throw new IllegalArgumentException("method " + method + " must have a request body.");
}
this.method = method;
this.body = body;
return this;
}
public Builder addHeader(String name, String value) {
headers.add(name, value);
return this;
}
public Builder url(String url) {
if (url == null) throw new NullPointerException("url == null");
// Silently replace web socket URLs with HTTP URLs.
if (url.regionMatches(true, 0, "ws:", 0, 3)) {
url = "http:" + url.substring(3);
} else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
url = "https:" + url.substring(4);
}
return url(HttpUrl.get(url));
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
複製代碼
注意到get()和post(RequestBody body)都是對method方法的包裝,method方法內部對請求方式和請求體進行了校驗,好比get請求不能有請求體、post請求必需要請求體等。其餘比較好理解,再也不贅述。框架
接着看HttpClient的newCall方法:異步
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
複製代碼
跟進RealCall的newRealCall方法:socket
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.transmitter = new Transmitter(client, call);
return call;
}
複製代碼
可見HttpClient的newCall方法得到Call實際是RealCall。RealCall就是準備執行的請求,是對接口Call的實現。其內部持有OkHttpClient實例、Request實例。而且這裏還建立了Transmitter給RealCall的transmitter賦值。
Transmitter意爲發射器,是應用層和網絡層的橋樑,在進行 鏈接、真正發出請求和讀取響應中起到很重要的做用,看下構造方法:
public Transmitter(OkHttpClient client, Call call) {
this.client = client;
this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool());
this.call = call;
this.eventListener = client.eventListenerFactory().create(call);
this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
}
複製代碼
Transmitter內部持有OkHttpClient、鏈接池、call、事件監聽器。
再回頭看RealCall實現的接口Call:
// 已準備要執行的請求。因爲表示單個請求/響應對(流),所以沒法執行兩次
public interface Call extends Cloneable {
...
//同步請求,會阻塞
Response execute() throws IOException;
//異步請求
void enqueue(Callback responseCallback);
//取消請求,已經完成的不能取消。
void cancel();
boolean isExecuted();
boolean isCanceled();
Timeout timeout();
...
interface Factory {
Call newCall(Request request);
}
}
複製代碼
主要是定義請求的執行動做和狀態。RealCall對Call的具體實現,在後面執行流程中說明。
好了,請求的建立就到這裏了。
執行分爲同步和異步,這裏先從 同步請求 開始分析,即RealCall的execute方法:
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.timeoutEnter();//超時計時開始
transmitter.callStart();//回調請求監聽器的請求開始
try {
client.dispatcher().executed(this);//放入隊列
return getResponseWithInterceptorChain();//執行請求獲取結果
} finally {
client.dispatcher().finished(this);//請求結束
}
}
複製代碼
首先判斷 若是已經執行,就會拋出異常。這就是一個請求只能執行一次的緣由。而後回調請求監聽器的請求開始。而後調用client的調度器Dispatcher的executed方法:
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
複製代碼
很簡單,請求放入一個雙端隊列runningSyncCalls中,表示正在執行的同步請求。
而後返回了getResponseWithInterceptorChain()的結果Response,能夠猜到,同步請求真正的請求流程是在getResponseWithInterceptorChain方法中。 最後請求結束,會走Dispatcher的finished(Deque calls, T call)方法,:
//結束 異步請求
void finished(AsyncCall call) {
//callsPerHost-1
call.callsPerHost().decrementAndGet();
finished(runningAsyncCalls, call);
}
//結束 同步請求
void finished(RealCall call) {
finished(runningSyncCalls, call);
}
//異步、同步的結束,都會走到這裏:從running中移除 並 調用promoteAndExecute
private <T> void finished(Deque<T> calls, T call) {
...
synchronized (this) {
//從隊列中移除
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
idleCallback = this.idleCallback;
}
boolean isRunning = promoteAndExecute();
...
}
複製代碼
從隊列中移除call,而後執行了 promoteAndExecute(),這裏先不跟進去了後面會講到。
到這裏,咱們知道了,同步請求走的是getResponseWithInterceptorChain()方法;
咱們再來看 異步請求,即RealCall的enqueue方法:
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();//回調請求監聽器的請求開始
client.dispatcher().enqueue(new AsyncCall(responseCallback));//請求調度
}
複製代碼
一樣先判斷是否已請求過,回調請求開始。而後調用Dispatcher的enqueue方法,參數接受的是AsyncCall,AsyncCall繼承NamedRunnable,NamedRunnable實現自Runnable,即AsyncCall就是個Runnable,能夠想到它是會在線程或線程池執行run方法的。run方法在AsyncCall沒看到啊,實際是在在NamedRunnable中:
//知道當前線程名字的Runnable
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
複製代碼
run調用 抽象方法execute(),execute()在AsyncCall是有實現的,這裏先不看。
咱們繼續去看Dispatcher的enqueue方法:
void enqueue(AsyncCall call) {
synchronized (this) {
//存入等待執行的隊列
readyAsyncCalls.add(call);
// 相同host的請求,共用一個 調用計數
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
promoteAndExecute();
}
//從 runningAsyncCalls或者readyAsyncCalls中找到相同host的請求
private AsyncCall findExistingCallWithHost(String host) {
for (AsyncCall existingCall : runningAsyncCalls) {
if (existingCall.host().equals(host)) return existingCall;
}
for (AsyncCall existingCall : readyAsyncCalls) {
if (existingCall.host().equals(host)) return existingCall;
}
return null;
}
複製代碼
先把請求放入雙端隊列readyAsyncCalls中,表示等待執行的異步請求。爲啥是等待執行呢?先留一個疑問。 接着從 正在執行的請求runningAsyncCalls 或 等待執行的請求readyAsyncCalls 中找到是相同host的請求,把callsPerHost重用給當前請求。callsPerHost看名字感受像是 擁有相同host的請求的數量,而且注意到類型是AtomicInteger,聲明以下:
private volatile AtomicInteger callsPerHost = new AtomicInteger(0);
複製代碼
因此,相同host的請求是共享callsPerHost的,爲了後面判斷host併發作準備。
繼續看,接着調用了promoteAndExecute(),前面看的finish方法也有調用,這裏能夠跟進看看了:
//調度的核心方法:在 控制異步併發 的策略基礎上,使用線程池 執行異步請求
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; //最大併發數64
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; //Host最大併發數5
i.remove();//從等待隊列中移除
asyncCall.callsPerHost().incrementAndGet();//Host併發數+1
executableCalls.add(asyncCall);//加入 可執行請求 的集合
runningAsyncCalls.add(asyncCall);//加入 正在執行的異步請求隊列
}
isRunning = runningCallsCount() > 0;//正在執行的異步/同步 請求數 >0
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());//可執行的請求
}
return isRunning;
}
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
複製代碼
遍歷readyAsyncCalls,先進行兩個檢查:正在執行的異步請求runningAsyncCalls數量大於最大併發請求數64就break,或者 相同host請求的數量大於5,就continue。若是檢查都經過,就從等待隊列中移除,callsPerHost自增1,放入 可執行的集合executableCalls,並添加到隊列runningAsyncCalls中,表示正在執行的異步請求。 這裏就解釋了 異步請求等待隊列的意義了,就是爲了控制最大併發數的緩衝:異步請求併發數達到6四、相同host的異步請求達到5,都要放入等待隊列。
遍歷完後 把executableCalls中的請求都走executeOn方法:
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
executorService.execute(this);//在線程池執行asyncCall
success = true;
} catch (RejectedExecutionException e) {
...
transmitter.noMoreExchanges(ioException);
responseCallback.onFailure(RealCall.this, ioException);//回調失敗
} finally {
if (!success) {
client.dispatcher().finished(this); //執行發生異常,結束
}
}
}
//線程池的定義
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
複製代碼
executeOn方法很簡單:使用相似CachedThreadPool的線程池 執行請求RealCall。若是執行失敗,也會調用dispatcher的finished(Deque calls, T call)方法。
前面分析過,AsyncCall的run方法會走到execute()方法,來看下:
protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();//超時計時開始
try {
Response response = getResponseWithInterceptorChain();////執行請求獲取結果
responseCallback.onResponse(RealCall.this, response);//回調結果
} catch (IOException e) {
...
responseCallback.onFailure(RealCall.this, canceledException);//回調失敗
...
} finally {
client.dispatcher().finished(this);//請求結束
}
}
複製代碼
咱們發現,這裏和 同步請求 就很像了,一樣是調用getResponseWithInterceptorChain()方法來獲取結果Response,不一樣點是使用responseCallback把結果回調出去,最後請求結束也是調用了dispatcher的finish方法。
另外,前面說過,finish方法中也調用了promoteAndExecute()方法,說明 同步/異步 請求 結束後 也會從新調度當前的異步請求。
好了,到這裏咱們把 調度流程 梳理下:
重點來啦!
經過上面分析指導,不管同步仍是異步請求,最終的執行都是在RealCall的getResponseWithInterceptorChain()方法,只不過異步請求 須要先經過Dispatcher進行併發控制和線程池處理。那麼就來看看getResponseWithInterceptorChain():
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors()); //使用者配置的 應用攔截器,最早攔截
interceptors.add(new RetryAndFollowUpInterceptor(client));//重試跟進攔截器
interceptors.add(new BridgeInterceptor(client.cookieJar()));//橋攔截器
interceptors.add(new CacheInterceptor(client.internalCache()));//緩存攔截器
interceptors.add(new ConnectInterceptor(client)); //鏈接攔截器
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors()); //使用者配置的網絡攔截器
}
interceptors.add(new CallServerInterceptor(forWebSocket)); //請求服務攔截器
//攔截器鏈
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
Response response = chain.proceed(originalRequest);//鏈 開始執行
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
複製代碼
首先是 把
依次 添加到集合interceptors中。而後使用interceptors、transmitter、originalRequest等建立了攔截器鏈RealInterceptorChain實例,最後用proceed方法獲取到請求的結果Response。
在上一篇 使用方法中有提到攔截器Interceptor,那裏配置的攔截器 實際就是 應用攔截器:client.interceptors(),是最先被添加到interceptors中。那麼到底 攔截器是個啥呢?chain.proceed是如何獲取到結果的呢?不着急,咱們先看看Interceptor類:
//攔截器
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
//攔截器鏈
interface Chain {
Request request();
//Chain的核心方法
Response proceed(Request request) throws IOException;
//返回請求執行的 鏈接. 僅網絡攔截器可用; 應用攔截器就是null.
@Nullable Connection connection();
Call call();
int connectTimeoutMillis();
Chain withConnectTimeout(int timeout, TimeUnit unit);
int readTimeoutMillis();
Chain withReadTimeout(int timeout, TimeUnit unit);
int writeTimeoutMillis();
Chain withWriteTimeout(int timeout, TimeUnit unit);
}
}
複製代碼
Interceptor是個接口類,只有一個intercept方法,參數是Chain對象。再注意到 內部接口類Chain -- 攔截器鏈,有個proceed方法,參數是Request對象,返回值是Response,那麼這個方法的實現就是請求的處理過程了。Chain的惟一實現類就是RealInterceptorChain,負責把全部攔截器串聯起來,proceed方法就是串聯的操做。
上述一系列的攔截器都是Interceptor的實現類,這裏先貼出上一篇中實現的應用攔截器(其餘攔截器的實現暫不去跟進):
new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String url = request.url().toString();
Log.i(TAG, "intercept: proceed start: url"+ url+ ", at "+System.currentTimeMillis());
Response response = chain.proceed(request);
ResponseBody body = response.body();
Log.i(TAG, "intercept: proceed end: url"+ url+ ", at "+System.currentTimeMillis());
return response;
}
}
複製代碼
在intercept方法中咱們調用chain.proceed方法獲取告終果 並在先後打印了一些日誌,那這個Chain實例是哪來的呢?intercept方法啥時候被調用的呢?— — 咱們再回頭看getResponseWithInterceptorChain方法,全部攔截器都被傳入RealInterceptorChain,能夠猜測到,一定是RealInterceptorChain的proceed方法內部調用了攔截器的intercept方法。 那麼就來看看吧:
@Override public Response proceed(Request request) throws IOException {
return proceed(request, transmitter, exchange);
}
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.exchange != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (exchange != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;
}
複製代碼
在實例化RealInterceptorChain時 index賦值是0,exchange是null,因此前面三個if都沒走進去。而後獲取了第一個攔截器,也就是咱們配置的應用攔截器,調用了它的interceptor方法,並返回和校驗告終果。這裏證明了咱們猜測。同時注意到,調用 應用攔截器的interceptor方法傳入的參數:攔截器鏈實例next,next就是把index + 1而已,其餘參數和當前實例是同樣的。也就是說 在咱們的應用攔截器中調用的是 next的proceed方法。
進一步,next的proceed方法中 一樣會獲取interceptors的index=1的攔截器,即RetryAndFollowUpInterceptor實例,而後調用其interceptor方法,參數是index+1即index=2的chain。跟進RetryAndFollowUpInterceptor的代碼發現,interceptor方法內部也是有調用chain的proceed方法。這樣就會依次傳遞下去,直到最後一個攔截器CallServerInterceptor。
實際上 除了最後一個攔截器CallServerInterceptor以外,全部攔截器的interceptor方法都調用了 傳入 chain的proceed方法。每一個攔截器在chain的proceed方法 先後 處理了本身負責的工做。例如咱們的應用攔截器,在chain的proceed方法前 打印了request信息的日誌,chain的proceed方法獲取結果 以後 打印了response信息的日誌。每一個攔截器interceptor方法在 調用chain的proceed方法時 都是爲了獲取下一個攔截器處理的response,而後返回給上一個攔截器。
邏輯總結以下圖:
這就是 okhttp執行流程的核心了,總體流程以下:
不知你有沒有發現,這一過程 和 公司工做生產流程 很像:
而不一樣的攔截器,在網絡請求這一任務中,就扮演着不一樣的角色。可能okhttp的做者寫攔截器的靈感就來源於生活吧,哈哈。
攔截器 | 做用 |
---|---|
應用攔截器 | 處理原始請求和最終的響應:能夠添加自定義header、通用參數、參數加密、網關接入等等。 |
RetryAndFollowUpInterceptor | 處理錯誤重試和重定向 |
BridgeInterceptor | 應用層和網絡層的橋接攔截器,主要工做是爲請求添加cookie、添加固定的header,好比Host、Content-Length、Content-Type、User-Agent等等,而後保存響應結果的cookie,若是響應使用gzip壓縮過,則還須要進行解壓。 |
CacheInterceptor | 緩存攔截器,獲取緩存、更新緩存。若是命中緩存則不會發起網絡請求。 |
ConnectInterceptor | 鏈接攔截器,內部會維護一個鏈接池,負責鏈接複用、建立鏈接(三次握手等等)、釋放鏈接以及建立鏈接上的socket流。 |
網絡攔截器 | 用戶自定義攔截器,一般用於監控網絡層的數據傳輸。 |
CallServerInterceptor | 請求攔截器,在前置準備工做完成後,真正發起網絡請求,進行IO讀寫。 |
這裏先大概知道每一個攔截器的角色任務,下一篇將會詳細分析每一個攔截器,以及重要知識點--緩存和鏈接池。
那麼,咱們對okhttp執行流程的源碼分析,到這裏也結束了。
如今經過兩篇文章,咱們已經掌握了okhttp的基本用法,而且經過閱讀源碼瞭解了okhttp總的執行流程——請求的建立、調度、攔截器鏈處理。接下來的文章,會深刻到每一個攔截器的具體實現,學習okhttp更多的高級使用技巧,感興趣的朋友請繼續關注。
.
歡迎 關注個人 公.衆.號
![]()