Android之OKHttp原始碼解析
一、OKHttp的基本使用
基本的使用流程如下 ```java // 例項OkHttpClient var okHttpClient = OkHttpClient() // 構建請求體 val body = FormBody.Builder().build() // 生成Request val request = Request.Builder().url("api地址").post(body).build() // 同步請求 val resopnse = okHttpClient.newCall(request).execute() // 獲取同步請求結果 String retJson = response.body().string(); // 非同步請求 okHttpClient.newCall(request).enqueue(object : Callback{ override fun onFailure(call: Call, e: IOException) { //請求失敗 }
override fun onResponse(call: Call, response: Response) {
//請求成功
}
}) ```
二、使用流程原始碼分析
同步請求流程分析 ```java // newCall例項一個RealCall @Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false / for web socket /); } // 執行realCall的execute @Override public Response execute() throws IOException { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } transmitter.timeoutEnter(); transmitter.callStart(); try { // 從okHttpClient中取出分發器呼叫executed client.dispatcher().executed(this); // 直接呼叫RealCall的攔截器 執行流程後面會講到 return getResponseWithInterceptorChain(); } finally { client.dispatcher().finished(this); } }
//Dispatcher中將 RealCall 放置 runningSyncCalls 同步雙向佇列 synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
```
非同步請求流程分析
```java // RealCall.java
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
// 這裡傳入一個AsyncCall
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
這裡與同步請求的
excute```有些不同
1. 呼叫的是分發器Dispatcher的enquene函式
2. 並沒有開始執行攔截器
那非同步請求流程中Dispatcher中做了什麼?
三、OKHttp分發器Dispatcher
從上面的執行流程原始碼我們可以瞭解到在進行同步請求excute
時只是呼叫了Dispatcher的executed
方法,將同步請求放置到同步雙端佇列中,這裡並沒有體現"分發"的作用,而在進行非同步請求enquene
時,呼叫了Dispatcher的enqueue
方法,這裡接著看原始碼:
```java
// Dispatcher.java
// 用於放置等待中的非同步任務的等待任務佇列
private final Deque
// 用於放置執行中的非同步任務的佇列
private final Deque
// 用於放置執行中的同步任務佇列
private final Deque
// 執行緒池 private @Nullable ExecutorService executorService; // 可以通過建構函式進行執行緒池賦值 public Dispatcher(ExecutorService executorService) { this.executorService = executorService; }
void enqueue(AsyncCall call) { synchronized (this) { //將任務放置在等待佇列中 readyAsyncCalls.add(call);
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
} // 根據佇列狀態協調處理任務 promoteAndExecute(); }
private boolean promoteAndExecute() { assert (!Thread.holdsLock(this));
List
for (int i = 0, size = executableCalls.size(); i < size; i++) { AsyncCall asyncCall = executableCalls.get(i); // 呼叫執行函式 傳入執行服務執行緒池 asyncCall.executeOn(executorService()); }
return isRunning; }
public synchronized ExecutorService executorService() { // 如果當前執行緒池為null,則建立 if (executorService == null) { // 建立一個跟CachedThreadPool大致相同的執行緒池 executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false)); } return executorService; }
```
首先會將非同步任務儲存到readyAsyncCalls
等待佇列中,其後會呼叫promoteAndExecute
進行任務的分發,根據執行佇列的請求數量最大閾值和請求相同host的數量進行一個條件判斷,根據結果決定要不要把任務放置runningAsyncCalls
執行佇列中,以及直接呼叫executorService
建立執行緒池用於任務的執行,到這裡我們可以總結Dispatcher
的任務就是管理三個任務佇列的任務分發以及一個執行緒池的建立。
asyncCall.executeOn(executorService())
的執行邏輯如下:
```java
//AsyncCall.java
void executeOn(ExecutorService executorService) { assert (!Thread.holdsLock(client.dispatcher())); boolean success = false; try { //執行緒池執行任務 executorService.execute(this); success = true; } catch (RejectedExecutionException e) { InterruptedIOException ioException = new InterruptedIOException("executor rejected"); ioException.initCause(e); transmitter.noMoreExchanges(ioException); responseCallback.onFailure(RealCall.this, ioException); } finally { if (!success) { client.dispatcher().finished(this); // This call is no longer running! } } }
//AsnycCall執行時的核心邏輯
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
//執行攔截器
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} catch (Throwable t) {
cancel();
if (!signalledCallback) {
IOException canceledException = new IOException("canceled due to " + t);
canceledException.addSuppressed(t);
responseCallback.onFailure(RealCall.this, canceledException);
}
throw t;
} finally {
//非同步任務完成時通知分發器中的佇列移除任務
client.dispatcher().finished(this);
}
}
```
到這裡,我們基本理清楚了非同步呼叫的一個鏈路:
那AsyncCall.excute()
內部的攔截器又是如何開始工作的呢?
四、OKHttp攔截器
```java
Response getResponseWithInterceptorChain() throws IOException {
// 攔截器集合
List
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);
}
}
}
先說一下責任鏈是如何呼叫起來的,在`getResponseWithInterceptorChain`中會把所有攔截器裝進集合中,再將攔截器集合以及集合的初始索引也就是0等一些引數傳入到例項的責任鏈物件`RealInterceptorChain`,然後呼叫責任鏈物件的`procrss`開啟攔截器執行
java
// 責任鏈物件建構函式
public RealInterceptorChain(List
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"); }
// 例項化責任鏈物件,將攔截器集合中的索引+1,也就是當前責任鏈物件的下一個責任鏈,對應下一個攔截器
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
// 取出當前責任鏈對應的攔截器
Interceptor interceptor = interceptors.get(index);
// 在當前責任鏈對應的攔截器呼叫intercept函式中傳入下一個責任鏈物件
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; }
//重試攔截器 public final class RetryAndFollowUpInterceptor implements Interceptor { /* * How many redirects and auth challenges should we attempt? Chrome follows 21 redirects; Firefox, * curl, and wget follow 20; Safari follows 16; and HTTP/1.0 recommends 5. / private static final int MAX_FOLLOW_UPS = 20;
private final OkHttpClient client;
public RetryAndFollowUpInterceptor(OkHttpClient client) { this.client = client; }
@Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); RealInterceptorChain realChain = (RealInterceptorChain) chain; Transmitter transmitter = realChain.transmitter();
int followUpCount = 0;
Response priorResponse = null;
while (true) {
transmitter.prepareToConnect(request);
if (transmitter.isCanceled()) {
throw new IOException("Canceled");
}
Response response;
boolean success = false;
try {
// 執行下一個責任鏈物件的proceed方法
response = realChain.proceed(request, transmitter, null);
success = true;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), transmitter, false, request)) {
throw e.getFirstConnectException();
}
continue;
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, transmitter, requestSendStarted, request)) throw e;
continue;
} finally {
// The network call threw an exception. Release any resources.
if (!success) {
transmitter.exchangeDoneDueToException();
}
}
// Attach the prior response if it exists. Such responses never have a body.
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
Exchange exchange = Internal.instance.exchange(response);
Route route = exchange != null ? exchange.connection().route() : null;
Request followUp = followUpRequest(response, route);
if (followUp == null) {
if (exchange != null && exchange.isDuplex()) {
transmitter.timeoutEarlyExit();
}
return response;
}
RequestBody followUpBody = followUp.body();
if (followUpBody != null && followUpBody.isOneShot()) {
return response;
}
closeQuietly(response.body());
if (transmitter.hasExchange()) {
exchange.detachWithViolence();
}
if (++followUpCount > MAX_FOLLOW_UPS) {
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
request = followUp;
priorResponse = response;
}
}
``
每一個責任鏈物件都對應一個攔截器,比如在我們沒有自定義攔截器時,初始責任鏈0對應攔截器集合索引0,也就是重試攔截器,在重試攔截器的
intercept中又呼叫下一個責任鏈物件1的
procees,也就會對應執行攔截器集合中索引為1橋接攔截器的
intercept,以此類推,就會完成整個責任鏈節點的呼叫,但是在責任鏈的呼叫鏈路中,不一定會全部執行,在一些場景下,攔截器可能會直接返回一個
response物件結束責任鏈呼叫,下面會講到,在重試攔截器中,會進入一個
while(true)`迴圈,重複執行重試攔截器後續的攔截器,如果開啟重試機制則會直到達到重試閾值或返回了一個滿足條件的結果。
橋接攔截器BridgeInterceptor ```java public final class BridgeInterceptor implements Interceptor { private final CookieJar cookieJar;
public BridgeInterceptor(CookieJar cookieJar) { this.cookieJar = cookieJar; }
@Override public Response intercept(Chain chain) throws IOException { Request userRequest = chain.request(); Request.Builder requestBuilder = userRequest.newBuilder();
RequestBody body = userRequest.body();
if (body != null) {
MediaType contentType = body.contentType();
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString());
}
long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {
requestBuilder.header("Transfer-Encoding", "chunked");
requestBuilder.removeHeader("Content-Length");
}
}
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
Response networkResponse = chain.proceed(requestBuilder.build());
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);
String contentType = networkResponse.header("Content-Type");
responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
}
return responseBuilder.build();
} ``` 橋接攔截器的作用從程式碼中可以看出,主要是對請求和響應進行一個包裝,形成規範。
快取攔截器CacheInterceptor ```java /* Serves requests from the cache and writes responses to the cache. / public final class CacheInterceptor implements Interceptor { final @Nullable InternalCache cache;
public CacheInterceptor(@Nullable InternalCache cache) { this.cache = cache; }
@Override public Response intercept(Chain chain) throws IOException { Response cacheCandidate = cache != null ? cache.get(chain.request()) : null;
long now = System.currentTimeMillis();
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
if (cache != null) {
cache.trackResponse(strategy);
}
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
}
// 如果請求不開啟網路且不使用快取
if (networkRequest == null && cacheResponse == null) {
// 直接返回一個response結束責任鏈
return new Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(Util.EMPTY_RESPONSE)
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
}
// 如果僅僅不開啟網路,但是開啟了快取,直接返回快取的結果
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
Response networkResponse = null;
try {
//下一個責任鏈呼叫,對應ConnectInterceptor
networkResponse = chain.proceed(networkRequest);
} finally {
// If we're crashing on I/O or otherwise, don't leak the cache body.
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
// If we have a cache response too, then we're doing a conditional get.
if (cacheResponse != null) {
if (networkResponse.code() == HTTP_NOT_MODIFIED) {
Response response = cacheResponse.newBuilder()
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.sentRequestAtMillis(networkResponse.sentRequestAtMillis())
.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
networkResponse.body().close();
// Update the cache after combining headers but before stripping the
// Content-Encoding header (as performed by initContentStream()).
cache.trackConditionalCacheHit();
cache.update(cacheResponse, response);
return response;
} else {
closeQuietly(cacheResponse.body());
}
}
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
if (cache != null) {
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
// Offer this request to the cache.
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
cache.remove(networkRequest);
} catch (IOException ignored) {
// The cache cannot be written.
}
}
}
return response;
} ``` 從程式碼中可以看出,快取攔截器在一些場景下回直接中斷攔截器的呼叫,返回結果。
連線攔截器ConnectInterceptor 連線攔截器是攔截器中比較關鍵的一環,涉及到了連線池的管理 ```java /* Opens a connection to the target server and proceeds to the next interceptor. / public final class ConnectInterceptor implements Interceptor { public final OkHttpClient client;
public ConnectInterceptor(OkHttpClient client) { this.client = client; }
@Override public Response intercept(Chain chain) throws IOException { RealInterceptorChain realChain = (RealInterceptorChain) chain; Request request = realChain.request(); Transmitter transmitter = realChain.transmitter();
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET");
Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks);
return realChain.proceed(request, transmitter, exchange);
}
}
連線的獲取是在`transmitter.newExchange()`執行到ExChangeFinder中的`findConnection()`
java
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
boolean foundPooledConnection = false;
RealConnection result = null;
Route selectedRoute = null;
RealConnection releasedConnection;
Socket toClose;
synchronized (connectionPool) {
if (transmitter.isCanceled()) throw new IOException("Canceled");
hasStreamFailure = false; // This is a fresh attempt.
// 獲取一個已經存在的連線
releasedConnection = transmitter.connection;
// 已經存在的連線可能已經不可用
toClose = transmitter.connection != null && transmitter.connection.noNewExchanges
? transmitter.releaseConnectionNoEvents()
: null;
if (transmitter.connection != null) {
//存在的連線可用
result = transmitter.connection;
releasedConnection = null;
}
if (result == null) {
// 嘗試從連線池中取獲取
if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, null, false)) {
foundPooledConnection = true;
result = transmitter.connection;
} else if (nextRouteToTry != null) {
selectedRoute = nextRouteToTry;
nextRouteToTry = null;
} else if (retryCurrentRoute()) {
selectedRoute = transmitter.connection.route();
}
}
} closeQuietly(toClose);
if (releasedConnection != null) { eventListener.connectionReleased(call, releasedConnection); } if (foundPooledConnection) { eventListener.connectionAcquired(call, result); } if (result != null) { // 已經有存在的連線可複用 直接返回 return result; }
// If we need a route selection, make one. This is a blocking operation. boolean newRouteSelection = false; if (selectedRoute == null && (routeSelection == null || !routeSelection.hasNext())) { newRouteSelection = true; routeSelection = routeSelector.next(); }
List
if (newRouteSelection) {
// Now that we have a set of IP addresses, make another attempt at getting a connection from
// the pool. This could match due to connection coalescing.
routes = routeSelection.getAll();
if (connectionPool.transmitterAcquirePooledConnection(
address, transmitter, routes, false)) {
foundPooledConnection = true;
result = transmitter.connection;
}
}
if (!foundPooledConnection) {
if (selectedRoute == null) {
selectedRoute = routeSelection.next();
}
// 沒有可用連線則新建
result = new RealConnection(connectionPool, selectedRoute);
connectingConnection = result;
}
}
// If we found a pooled connection on the 2nd time around, we're done. if (foundPooledConnection) { eventListener.connectionAcquired(call, result); return result; }
// Do TCP + TLS handshakes. This is a blocking operation. result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis, connectionRetryEnabled, call, eventListener); connectionPool.routeDatabase.connected(result.route());
Socket socket = null; synchronized (connectionPool) { connectingConnection = null; // Last attempt at connection coalescing, which only occurs if we attempted multiple // concurrent connections to the same host. if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, routes, true)) { // We lost the race! Close the connection we created and return the pooled connection. result.noNewExchanges = true; socket = result.socket(); result = transmitter.connection;
// It's possible for us to obtain a coalesced connection that is immediately unhealthy. In
// that case we will retry the route we just successfully connected with.
nextRouteToTry = selectedRoute;
} else {
// 將新建連線放置連線池
connectionPool.put(result);
transmitter.acquireConnectionNoEvents(result);
}
} closeQuietly(socket);
eventListener.connectionAcquired(call, result); return result; } ``` 一個連線的獲取流程為: 1. 嘗試使用當前連線,但是連線可能不用 2. 從連線池中獲取連線,如果有快取的話 3. 新建一個連線,並放置到連線池
而連線在連線池的釋放流程為:
```java
public final class RealConnectionPool {
private static final Executor executor = new ThreadPoolExecutor(0 /* corePoolSize */,
Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS,
new SynchronousQueue<>(), Util.threadFactory("OkHttp ConnectionPool", true));
// 將連線放置連線池
void put(RealConnection connection) {
assert (Thread.holdsLock(this));
if (!cleanupRunning) {
cleanupRunning = true;
// 執行緒池執行連線池的清理任務
executor.execute(cleanupRunnable);
}
// 將連線放置連線池
connections.add(connection);
}
}
// 連線池的清理任務
private final Runnable cleanupRunnable = () -> {
// 開啟迴圈檢測
while (true) {
// 清理方法
long waitNanos = cleanup(System.nanoTime());
if (waitNanos == -1) return;
if (waitNanos > 0) {
long waitMillis = waitNanos / 1000000L;
waitNanos -= (waitMillis * 1000000L);
synchronized (RealConnectionPool.this) {
try {
RealConnectionPool.this.wait(waitMillis, (int) waitNanos);
} catch (InterruptedException ignored) {
}
}
}
}
};
long cleanup(long now) { int inUseConnectionCount = 0; int idleConnectionCount = 0; RealConnection longestIdleConnection = null; long longestIdleDurationNs = Long.MIN_VALUE;
// Find either a connection to evict, or the time that the next eviction is due.
synchronized (this) {
for (Iterator
// If the connection is in use, keep searching.
if (pruneAndGetAllocationCount(connection, now) > 0) {
inUseConnectionCount++;
continue;
}
idleConnectionCount++;
// If the connection is ready to be evicted, we're done.
long idleDurationNs = now - connection.idleAtNanos;
if (idleDurationNs > longestIdleDurationNs) {
longestIdleDurationNs = idleDurationNs;
longestIdleConnection = connection;
}
}
if (longestIdleDurationNs >= this.keepAliveDurationNs
|| idleConnectionCount > this.maxIdleConnections) {
// 清理連線
connections.remove(longestIdleConnection);
} else if (idleConnectionCount > 0) {
// A connection will be ready to evict soon.
return keepAliveDurationNs - longestIdleDurationNs;
} else if (inUseConnectionCount > 0) {
// All connections are in use. It'll be at least the keep alive duration 'til we run again.
return keepAliveDurationNs;
} else {
// No connections, idle or in use.
cleanupRunning = false;
return -1;
}
}
closeQuietly(longestIdleConnection.socket());
// Cleanup again immediately.
return 0;
}
``
maxIdleConnections和
keepAliveDurationNs,分別表示最大允許的閒置的連線的數量和連線允許存活的最長的時間。預設空閒連線最大數目為5個,
keepalive` 時間最長為5分鐘。
請求服務攔截器CallServerInterceptor ```java public final class CallServerInterceptor implements Interceptor { private final boolean forWebSocket;
public CallServerInterceptor(boolean forWebSocket) { this.forWebSocket = forWebSocket; }
@Override public Response intercept(Chain chain) throws IOException { RealInterceptorChain realChain = (RealInterceptorChain) chain; Exchange exchange = realChain.exchange(); Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
exchange.writeRequestHeaders(request);
boolean responseHeadersStarted = false;
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
// If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
// Continue" response before transmitting the request body. If we don't get that, return
// what we did get (such as a 4xx response) without ever transmitting the request body.
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
exchange.flushRequest();
responseHeadersStarted = true;
exchange.responseHeadersStart();
responseBuilder = exchange.readResponseHeaders(true);
}
if (responseBuilder == null) {
if (request.body().isDuplex()) {
// Prepare a duplex body so that the application can send a request body later.
exchange.flushRequest();
BufferedSink bufferedRequestBody = Okio.buffer(
exchange.createRequestBody(request, true));
request.body().writeTo(bufferedRequestBody);
} else {
// Write the request body if the "Expect: 100-continue" expectation was met.
BufferedSink bufferedRequestBody = Okio.buffer(
exchange.createRequestBody(request, false));
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
}
} else {
exchange.noRequestBody();
if (!exchange.connection().isMultiplexed()) {
// If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
// from being reused. Otherwise we're still obligated to transmit the request body to
// leave the connection in a consistent state.
exchange.noNewExchangesOnConnection();
}
}
} else {
exchange.noRequestBody();
}
if (request.body() == null || !request.body().isDuplex()) {
exchange.finishRequest();
}
if (!responseHeadersStarted) {
exchange.responseHeadersStart();
}
if (responseBuilder == null) {
responseBuilder = exchange.readResponseHeaders(false);
}
Response response = responseBuilder
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
if (code == 100) {
// server sent a 100-continue even though we did not request one.
// try again to read the actual response
response = exchange.readResponseHeaders(false)
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
code = response.code();
}
exchange.responseHeadersEnd(response);
if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
response = response.newBuilder()
.body(exchange.openResponseBody(response))
.build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
exchange.noNewExchangesOnConnection();
}
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
}
}
``
請求服務攔截器是攔截器集合中的最後一環,網路請求也是在此進行的操作,在請求完成後會返回response進行回傳,最終就是
getResponseWithInterceptorChain`的返回結果。
至此,okHttp的解析就到這裡了,有不對的地方歡迎大家指出,篇幅有點長,有覺得有所幫助的話大家可以點贊收藏哦~