OKHttp源碼分析

前言

半年前閱讀了Volley源碼,可是如今主流網絡請求都是使用OkHttp + Retrofit + RxJava,所以打算好好研究下OkHttp的源碼(基於OkHttp3.14.1),記錄一下java

1、簡單使用

這裏只例舉基本的Get請求,詳細的請看官方文檔git

val client = OkHttpClient()  
fun syncGet(url: String) {
    val request = Request.Builder()
        .url(url)
        .build()
    val call = client.newCall(request)
    val response = call.execute()
    if (response.isSuccessful) {
        Log.d(TAG, "請求成功: " + response.body()!!.string())
    } else {
        Log.d(TAG, "請求失敗: " + response.message())
    }
}
fun asyncGet(url: String) {
    val request = Request.Builder()
        .url(url)
        .build()
    val call = client.newCall(request)
    call.enqueue(object  : Callback {
        override fun onFailure(call: Call, e: IOException) {
            Log.d(TAG, "錯誤: " + e.message)
        }
        override fun onResponse(call: Call, response: Response) {
            if (response.isSuccessful) {
                Log.d(TAG, "請求成功: " + response.body()!!.string())
            } else {
                Log.d(TAG, "請求失敗: " + response.message())
            }
        }
    })
}
複製代碼

由上可知,發送一個基本的get請求須要以下幾步github

  1. 建立OkHttpClient實例
  2. 建立Request實例
  3. 建立Call實例
  4. 調用call.execute或者call.enqueue執行同步或者異步請求

下面按照這五步探索下源碼web

2、OkHttpClient實例的建立

首先看看OkHttpClient的構造器設計模式

public OkHttpClient() {
    this(new Builder());
}

OkHttpClient(Builder builder) {
    // 主要是從builder中取出對應字段進行賦值,忽略
    ...
}
複製代碼

其擁有兩個構造器不過咱們只能直接調用無參的那個,另外一個主要給Builder的build方法使用的(典型的建造者模式),接着看看Builder的構造器數組

public Builder() {
    // 建立異步執行策略
    dispatcher = new Dispatcher();
    // 默認協議列表Http1.一、Http2.0
    protocols = DEFAULT_PROTOCOLS;
    // 鏈接規格,包括TLS(用於https)、CLEARTEXT(未加密用於http)
    connectionSpecs = DEFAULT_CONNECTION_SPECS;
    // 事件監聽,默認沒有
    eventListenerFactory = EventListener.factory(EventListener.NONE);
    // 代理選擇器
    proxySelector = ProxySelector.getDefault();
    // 使用空對象設計模式
    if (proxySelector == null) {
        proxySelector = new NullProxySelector();
    }
    // 提供Cookie策略的持久性
    cookieJar = CookieJar.NO_COOKIES;
    // socket工廠
    socketFactory = SocketFactory.getDefault();
    // hostname驗證器
    hostnameVerifier = OkHostnameVerifier.INSTANCE;
    // 證書標籤
    certificatePinner = CertificatePinner.DEFAULT;
    // 代理認證
    proxyAuthenticator = Authenticator.NONE;
    // 認證
    authenticator = Authenticator.NONE;
    // 鏈接池
    connectionPool = new ConnectionPool();
    // dns
    dns = Dns.SYSTEM;
    // 跟隨ssl重定向
    followSslRedirects = true;
    // 跟隨重定向
    followRedirects = true;
    // 當鏈接失敗時嘗試
    retryOnConnectionFailure = true;
    callTimeout = 0;
    // 鏈接、讀取、寫超時10秒
    connectTimeout = 10_000;
    readTimeout = 10_000;
    writeTimeout = 10_000;
    pingInterval = 0;
}

Builder(OkHttpClient okHttpClient) {
    // 從已有的OkHttpClient實例中取出對應的參數賦值給當前實例
    ...
}
複製代碼

Builder中的屬性到用到時再好好的研究,接着來看看第二步Request實例的建立緩存

3、Request實例的建立

Request實例經過Builder進行建立的,所以首先看看Request.Builder的構造器服務器

public Builder() {
    this.method = "GET";
    this.headers = new Headers.Builder();
}
Builder(Request request) {
    this.url = request.url;
    this.method = request.method;
    this.body = request.body;
    this.tags = request.tags.isEmpty()
            ? Collections.emptyMap()
            : new LinkedHashMap<>(request.tags);
    this.headers = request.headers.newBuilder();
}
複製代碼

其提供了兩個構造器,不過咱們只能調用無參的那個其內部設置了默認請求方法爲GET,而且建立了一個HeaderBuilder實例用於統一管理請求頭,第二個構造器用於Request實例中拷貝出對應參數賦值給當前Builder實例,接着看看其url方法和build方法cookie

public Builder url(String url) {
    if (url == null) throw new NullPointerException("url == null");
    // 默默的將web socket urls替換成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 Builder url(HttpUrl url) {
    if (url == null) throw new NullPointerException("url == null");
    this.url = url;
    return this;
}
public Request build() {
    if (url == null) throw new IllegalStateException("url == null");
    return new Request(this);
}
Request(Builder builder) {
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tags = Util.immutableMap(builder.tags);
}
複製代碼

其中url方法主要是將請求地址封裝成HttpUrl實例並賦值給成員url,build方法建立了Request實例。至此第二步結束了接着看看第三步Call實例的建立網絡

4、Call實例的建立

經過調用OkHttpClient實例的newCall()建立Call實例

// OkHttpClient.java
public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
}
// RealCall.java
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.transmitter = new Transmitter(client, call);
    return call;
}
// Transmitter.java
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);
    // 設置了AsyncTimeout的超時時間默認是0,下文execute方法執行時會用到
    this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
}
複製代碼

newCall方法返回了一個RealCall實例,而且初始化了其transmitter屬性(暫時不用管Transmitter的做用),而在Transmitter構造器中又初始化了connectionPool、eventListener屬性,其中Internal.instance在OkHttpClient這個類一加載時就初始化了

// OkHttpClient.java
Internal.instance = new Internal() {
    ...
    @Override
    public RealConnectionPool realConnectionPool(ConnectionPool connectionPool) {
        return connectionPool.delegate;
    }
    ...
}
複製代碼

接着主要看看client.connectionPool方法和eventListenerFactory方法

// OkHttpClient.java
public Builder() {
    connectionPool = new ConnectionPool();
}
public final class ConnectionPool {
    final RealConnectionPool delegate;
    public ConnectionPool() {
        this(5, 5, TimeUnit.MINUTES);
    }
    public ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
        this.delegate = new RealConnectionPool(maxIdleConnections, keepAliveDuration, timeUnit);
    }
    // 返回當前鏈接池的空閒鏈接數
    public int idleConnectionCount() {
        return delegate.idleConnectionCount();
    }
    // 返回當前鏈接池的總共鏈接數
    public int connectionCount() {
        return delegate.connectionCount();
    }
    // 關閉移除當前鏈接池中全部空閒的鏈接
    public void evictAll() {
        delegate.evictAll();
    }
}
// RealConnectionPool.java
public RealConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
    this.maxIdleConnections = maxIdleConnections;
    this.keepAliveDurationNs = timeUnit.toNanos(keepAliveDuration);
    if (keepAliveDuration <= 0) {
        throw new IllegalArgumentException("keepAliveDuration <= 0: " + keepAliveDuration);
    }
}
public ConnectionPool connectionPool() {
    return connectionPool;
}

public Builder() {
    eventListenerFactory = EventListener.factory(EventListener.NONE);
}
static EventListener.Factory factory(EventListener listener) {
    return call -> listener;
}
public EventListener.Factory eventListenerFactory() {
    return eventListenerFactory;
}
複製代碼

從上源碼能夠得出其實connectionPool最終實現是RealConnectionPool、eventListener默認是EventListener.NONE,至此RealCall實例也已經建立完畢了,接着進入最重要的一步execute或者enqueue,咱們先看看同步的狀況

5、call.execute()

咱們知道call實際上是一個RealCall實例,所以看看其execute方法

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);
    }
}
// Transmitter.java
public final class 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);
        // 設置了AsyncTimeout的超時時間默認是0
        this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
    }
    
    // AsyncTimeout具體實現就不深究了,只需知道當調用了enter方法後若是達到了設置的時間還沒調用
    // 就會調用timedOut方法,而這裏由於默認的callTimeout是0,所以不會超時
    private final AsyncTimeout timeout = new AsyncTimeout() {
        @Override 
        protected void timedOut() {
            cancel();
        }
    };
    public void timeoutEnter() {
        timeout.enter();
    }
    
    public void callStart() {
        // 建立了一個Throwable記錄了當前棧信息
        this.callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
        // 回調callStart,默認設置的沒處理任何事件
        eventListener.callStart(call);
    }
}


// Dispatcher.java
public final class Dispatcher {
    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
    synchronized void executed(RealCall call) {
        runningSyncCalls.add(call);
    }
}
複製代碼

首先會判斷一下當前call是否已經被執行過,若是已經被執行過了就會拋出異常,而後開啓WatchDog監聽Timeout,若是超時就會取消本次請求,接着記錄當前的棧信息並回調callStart,而後將當前RealCall實例加入到OkHttpClient實例內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);
        }
    }
}
複製代碼

該方法首先將OkHttpClient的全部Interceptor與框架本身的幾個Interceptor進行組合,而後建立RealInterceptorChain實例調用其proceed方法獲取到Response,所以網絡請求的主要邏輯就是在這個proceed方法中

// RealInterceptorChain
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange) throws IOException {
    // 默認index = 0,若是index超出了攔截器的總長就拋出錯誤
    if (index >= interceptors.size()) throw new AssertionError();
    calls++;
    // 這裏剛纔傳入的exchange爲null
    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 (this.exchange != null && calls > 1) {
        throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
                + " must call proceed() exactly once");
    }
    // 又建立了一個RealInterceptorChain實例,不過其index在原來基礎上加了1
    RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
            index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    // 取出一個Interceptor實例調用其intercept方法
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    if (exchange != null && index + 1 < interceptors.size() && next.calls != 1) {
        throw new IllegalStateException("network interceptor " + interceptor
                + " must call proceed() exactly once");
    }
    // 若是Interceptor返回了null那麼拋出NPE
    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;
}
複製代碼

該方法內部主要從interceptors中取出index位置上的一個Interceptor實例,而後建立一個index=index+1的RealInterceptorChain實例next,最後調用Interceptor實例的interceptor方法將next傳入,獲取到Response返回,那麼網絡請求重點其實在interceptor.intercept方法內,而默認index等於0,咱們的OkHttpClient本身又沒有設置Interceptor,因而會調用到RetryAndFollowUpInterceptor(負責失敗重試以及重定向)實例的intercept方法

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 {
            response = realChain.proceed(request, transmitter, null);
            // 表示請求成功可是多是一個重定向響應
            success = true;
        } catch (RouteException e) {
            // 嘗試經過路由鏈接失敗請求將不會發送,判斷是否須要進行重試
            if (!recover(e.getLastConnectException(), transmitter, false, request)) {
                throw e.getFirstConnectException();
            }
            continue;
        } catch (IOException e) {
            // 試圖與服務器通訊失敗,請求可能已經發送,判斷是否須要進行重試
            boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
            if (!recover(e, transmitter, requestSendStarted, request)) throw e;
            continue;
        } finally {
            // 若是請求沒有成功則釋放資源
            if (!success) {
                transmitter.exchangeDoneDueToException();
            }
        }
        // 若是上個響應存在(表示上個響應是一個重定向響應,其不會擁有響應體),構建一個新的Response實例
        // 將上個響應賦值給priorResponse屬性
        if (priorResponse != null) {
            response = response.newBuilder()
                    .priorResponse(priorResponse.newBuilder()
                            .body(null)
                            .build())
                    .build();
        }
        // 暫時不理解這個exchange是幹什麼用的??
        Exchange exchange = Internal.instance.exchange(response);
        Route route = exchange != null ? exchange.connection().route() : null;
        // 根據響應頭判斷是不是重定向,若是是就會新建一個Request實例返回
        Request followUp = followUpRequest(response, route);
        // 若是followUp爲空也就是沒有重定向那麼直接返回響應
        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;
    }
}
複製代碼

RetryAndFollowUpInterceptor主要作的就是重試以及處理重定向,內部會調用realChain.proceed調用下層Interceptor實例的intercept方法,當下層Interceptor拋出異常會判斷是否有重試的必要 ,當下層返回了一個Response,其會根據該Response判斷是否爲重定向響應,若是是就會建立新建一個Request實例,再次請求獲取到新的Response實例後將原先的Response賦值給其priorResponse屬性,以此循環直到請求成功(再也不重定向)、超出最大重定向數、拋出不可重試的異常。而後看看BridgeInterceptor

public final class BridgeInterceptor implements Interceptor {
    private final CookieJar cookieJar;
    // 這裏的CookieJar就是OkHttpClient的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();
        // 若是有請求體,而且請求頭若是沒有Content-Type、Content-length、Host、Connection就加上
        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");
        }
        // 而後若是沒有Accept-Encoding請求頭而且不是請求部分資源,那麼加上Accept-Encoding: gzip
        boolean transparentGzip = false;
        if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
            transparentGzip = true;
            requestBuilder.header("Accept-Encoding", "gzip");
        }
        // 從cookieJar中取出Cookie列表
        List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
        if (!cookies.isEmpty()) {
            requestBuilder.header("Cookie", cookieHeader(cookies));
        }
        // 沒有UserAgrent就添加爲okhttp/3.14.1
        if (userRequest.header("User-Agent") == null) {
            requestBuilder.header("User-Agent", Version.userAgent());
        }
        // 調用下一個Interceptor
        Response networkResponse = chain.proceed(requestBuilder.build());
        // 使用cookieJar保存cookie
        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");
            // 自動進行解壓,不過contentLength變成了-1
            responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
        }
        return responseBuilder.build();
    }
    private String cookieHeader(List<Cookie> cookies) {
        StringBuilder cookieHeader = new StringBuilder();
        for (int i = 0, size = cookies.size(); i < size; i++) {
            if (i > 0) {
                cookieHeader.append("; ");
            }
            Cookie cookie = cookies.get(i);
            cookieHeader.append(cookie.name()).append('=').append(cookie.value());
        }
        return cookieHeader.toString();
    }
}
複製代碼

BridgeInterceptor的邏輯很清晰,其作爲應用程序代碼與網絡代碼中間的橋樑,首先根據給用戶的Request實例建立一個添加了某些請求頭的Request實例;其次調用了chain.proceed執行下一個攔截器;最後將下層返回的Response實例構建成用戶須要的Response實例,此外上述代碼還告訴咱們若是想要持久化管理cookie能夠實現CookieJar這個接口設置給OkHttpClient,接着繼續看看下一層CacheInterceptor

public final class CacheInterceptor implements Interceptor {

    // 這個cache就是OkHttpClient裏面的internalCache
    final InternalCache cache;
    public CacheInterceptor(@Nullable InternalCache cache) {
        this.cache = cache;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        // 若是給OkHttpClient設置了InternalCache,那麼從裏面獲取緩存的響應
        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());
        }
        // 客戶端設置了only-if-cached,表示只使用緩存而緩存又沒有命中所以直接構建一個Response返回
        if (networkRequest == null && cacheResponse == null) {
            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();
        }
        // 緩存命中,構造一個Response實例並將去掉了body的cacheResponse賦值給該實例的cacheResponse屬性
        if (networkRequest == null) {
            return cacheResponse.newBuilder()
                    .cacheResponse(stripBody(cacheResponse))
                    .build();
        }
        Response networkResponse = null;
        try {
            networkResponse = chain.proceed(networkRequest);
        } finally {
            // 發生了異常須要將緩存響應體關閉
            if (networkResponse == null && cacheCandidate != null) {
                closeQuietly(cacheCandidate.body());
            }
        }
        // 若是有緩存響應而且響應碼是304,就根據返回的響應和緩存的響應構造一個新的響應而且更新下緩存
        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();
                cache.trackConditionalCacheHit();
                cache.update(cacheResponse, response);
                return response;
            } else {
                closeQuietly(cacheResponse.body());
            }
        }

        // 響應碼不是304,則構造一個新的Response將cacheResponse、networkResponse分別去掉body賦值給
        // cacheResponse和networkResponse
        Response response = networkResponse.newBuilder()
                .cacheResponse(stripBody(cacheResponse))
                .networkResponse(stripBody(networkResponse))
                .build();
        if (cache != null) {
            if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
                // 將最終響應放到cache中
                CacheRequest cacheRequest = cache.put(response);
                return cacheWritingResponse(cacheRequest, response);
            }
            if (HttpMethod.invalidatesCache(networkRequest.method())) {
                try {
                    cache.remove(networkRequest);
                } catch (IOException ignored) {
                }
            }
        }
        return response;
    }
}
public final class CacheStrategy {
    public static class Factory {
        public Factory(long nowMillis, Request request, Response cacheResponse) {
            this.nowMillis = nowMillis;
            this.request = request;
            this.cacheResponse = cacheResponse;
            // 根據緩存響應頭提取出一些緩存有關的信息
            if (cacheResponse != null) {
                this.sentRequestMillis = cacheResponse.sentRequestAtMillis();
                this.receivedResponseMillis = cacheResponse.receivedResponseAtMillis();
                Headers headers = cacheResponse.headers();
                for (int i = 0, size = headers.size(); i < size; i++) {
                    String fieldName = headers.name(i);
                    String value = headers.value(i);
                    if ("Date".equalsIgnoreCase(fieldName)) {
                        servedDate = HttpDate.parse(value);
                        servedDateString = value;
                    } else if ("Expires".equalsIgnoreCase(fieldName)) {
                        expires = HttpDate.parse(value);
                    } else if ("Last-Modified".equalsIgnoreCase(fieldName)) {
                        lastModified = HttpDate.parse(value);
                        lastModifiedString = value;
                    } else if ("ETag".equalsIgnoreCase(fieldName)) {
                        etag = value;
                    } else if ("Age".equalsIgnoreCase(fieldName)) {
                        ageSeconds = HttpHeaders.parseSeconds(value, -1);
                    }
                }
            }
        }
    }
}
public CacheStrategy get() {
    CacheStrategy candidate = getCandidate();
    if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {
        // 若是設置了onlyIfCached那麼在CacheInterceptor的intercept方法內部會直接構造一個響應碼爲504的Response
        return new CacheStrategy(null, null);
    }
    return candidate;
}
private CacheStrategy getCandidate() {
    // 沒有緩存響應就直接建立一個沒響應的CacheStrategy實例
    if (cacheResponse == null) {
        return new CacheStrategy(request, null);
    }
    // 丟棄緩存響應,若是請求是https而且缺乏必要的握手
    if (request.isHttps() && cacheResponse.handshake() == null) {
        return new CacheStrategy(request, null);
    }
    // 若是不該該使用緩存也丟棄緩存響應
    if (!isCacheable(cacheResponse, request)) {
        return new CacheStrategy(request, null);
    }
    CacheControl requestCaching = request.cacheControl();
    // 若是Request包含noCache請求頭,或者帶上了 If-Modified-Since、If-None-Match兩個請求頭也丟棄響應
    // 應該帶上這兩個請求頭表示客戶端在循環服務端資源是否發生變化,沒變化會返回304,所以不該該使用緩存
    if (requestCaching.noCache() || hasConditions(request)) {
        return new CacheStrategy(request, null);
    }
    CacheControl responseCaching = cacheResponse.cacheControl();
    long ageMillis = cacheResponseAge();
    long freshMillis = computeFreshnessLifetime();
    if (requestCaching.maxAgeSeconds() != -1) {
        freshMillis = Math.min(freshMillis, SECONDS.toMillis(requestCaching.maxAgeSeconds()));
    }
    long minFreshMillis = 0;
    if (requestCaching.minFreshSeconds() != -1) {
        minFreshMillis = SECONDS.toMillis(requestCaching.minFreshSeconds());
    }
    long maxStaleMillis = 0;
    if (!responseCaching.mustRevalidate() && requestCaching.maxStaleSeconds() != -1) {
        maxStaleMillis = SECONDS.toMillis(requestCaching.maxStaleSeconds());
    }
    // 根據時間判斷是否緩存命中,不知道具體是怎麼判斷的?
    if (!responseCaching.noCache() && ageMillis + minFreshMillis < freshMillis + maxStaleMillis) {
        Response.Builder builder = cacheResponse.newBuilder();
        if (ageMillis + minFreshMillis >= freshMillis) {
            builder.addHeader("Warning", "110 HttpURLConnection \"Response is stale\"");
        }
        long oneDayMillis = 24 * 60 * 60 * 1000L;
        if (ageMillis > oneDayMillis && isFreshnessLifetimeHeuristic()) {
            builder.addHeader("Warning", "113 HttpURLConnection \"Heuristic expiration\"");
        }
        return new CacheStrategy(null, builder.build());
    }
    // 添加If-None-Match、If-Modified-Since請求頭
    String conditionName;
    String conditionValue;
    if (etag != null) {
        conditionName = "If-None-Match";
        conditionValue = etag;
    } else if (lastModified != null) {
        conditionName = "If-Modified-Since";
        conditionValue = lastModifiedString;
    } else if (servedDate != null) {
        conditionName = "If-Modified-Since";
        conditionValue = servedDateString;
    } else {
        return new CacheStrategy(request, null);
    }
    Headers.Builder conditionalRequestHeaders = request.headers().newBuilder();
    Internal.instance.addLenient(conditionalRequestHeaders, conditionName, conditionValue);
    Request conditionalRequest = request.newBuilder()
            .headers(conditionalRequestHeaders.build())
            .build();
    return new CacheStrategy(conditionalRequest, cacheResponse);
}
複製代碼

CacheInterceptor的主要功能就是從InternalCache中取出保存的響應,而後根據請求和緩存的響應判斷緩存是否命中,命中就會直接構建一個新的響應返回,若是沒命中(因爲響應過時),則會根據緩存響應的ETag、LastModify等響應頭去構造當前的請求頭,這樣當服務器判斷資源沒變化時能夠直接返回304,框架也只須要更新下緩存的響應頭就能夠直接返回了。OkHttp爲咱們提供了一個Cache類(內部使用DiskLruCache實現)若是咱們須要可以緩存只須要進行以下設置.

val client = OkHttpClient.Builder().cache(Cache(cacheFile, 50 * 1000)).build()
複製代碼

接着看看下一個攔截器ConnectInterceptor

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();
        boolean doExtensiveHealthChecks = !request.method().equals("GET");
        Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks);
        return realChain.proceed(request, transmitter, exchange);
    }
}
複製代碼

ConnectIntercept代碼不多,可是作的事情不少,其會先去ConnectionPoll中尋找是否有合適的RealConnection,若是沒有找到會去請求dns服務器獲取目標IP再將目標IP封裝成一個Route實例而後建立一個RealConnection接着建立Socket實例併發起鏈接若是是Https請求還會發起握手,校驗證書,接着構建Http1ExchangeCodec實例,最後再去構建Exchange實例,接着再看看CallServerInterceptor

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生成對應的字節數組而且寫入到Buffer中
        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 ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
                exchange.flushRequest();
                responseHeadersStarted = true;
                exchange.responseHeadersStart();
                responseBuilder = exchange.readResponseHeaders(true);
            }
            if (responseBuilder == null) {
                if (request.body().isDuplex()) {
                    exchange.flushRequest();
                    BufferedSink bufferedRequestBody = Okio.buffer(
                            exchange.createRequestBody(request, true));
                    request.body().writeTo(bufferedRequestBody);
                } else {
                    BufferedSink bufferedRequestBody = Okio.buffer(
                            exchange.createRequestBody(request, false));
                    request.body().writeTo(bufferedRequestBody);
                    bufferedRequestBody.close();
                }
            } else {
                exchange.noRequestBody();
                if (!exchange.connection().isMultiplexed()) {
                    exchange.noNewExchangesOnConnection();
                }
            }
        } else {
            exchange.noRequestBody();
        }
        if (request.body() == null || !request.body().isDuplex()) {
            // 將Buffer中的數據寫給服務端
            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) {
            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) {
            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;
    }
}
複製代碼

CallServerInterceptor真正的進行了網絡請求,會根據Request實例構建出Http請求,獲取到Http響應後再構建出HttpResponse,網絡請求成功後會接着執行前幾個Interceptor的剩餘代碼,這裏就不看了。直接回到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);
    }
}
void finished(RealCall call) {
    finished(runningSyncCalls, call);
}
private <T> void finished(Deque<T> calls, T call) {
    Runnable idleCallback;
    synchronized (this) {
        if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
        idleCallback = this.idleCallback;
    }
    boolean isRunning = promoteAndExecute();
    if (!isRunning && idleCallback != null) {
        idleCallback.run();
    }
}
複製代碼

能夠看出當一次同步請求結束後,會將RealCall中隊列中移除,而後啓動正在等待的異步請求,若是沒有異步請求會回調IdleCallback。接着看看異步請求過程

6、call.enqueue()

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));
}
複製代碼

這裏都和execute同樣只是最後調用了Dispatcher的enqueue方法,不過傳入的是AsyncCall實例

//Dispatcher.java
void enqueue(AsyncCall call) {
    synchronized (this) {
        // 將call加入到隊列中去
        readyAsyncCalls.add(call);
        if (!call.get().forWebSocket) {
            // 剛剛建立的call不是使用webSocket因此進入這裏
            AsyncCall existingCall = findExistingCallWithHost(call.host());
            // 目的只是爲了統計每一個Host有幾個AsyncCall
            if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
        }
    }
    promoteAndExecute();
}
// 從正在執行或者等待執行的call隊列中取出host屬性爲host的AsyncCall實例
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;
}
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();
            // 若是已經達到最大請求數64就中止執行
            if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
            // 若是每一個Host達到了最大請求數5個就跳過該call
            if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
            i.remove();
            // 每一個端口請求計數加1
            asyncCall.callsPerHost().incrementAndGet();
            executableCalls.add(asyncCall);
            runningAsyncCalls.add(asyncCall);
        }
        isRunning = runningCallsCount() > 0;
    }
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
        AsyncCall asyncCall = executableCalls.get(i);
        // 建立一個線程池,而後執行AsyncCall的execute方法
        asyncCall.executeOn(executorService());
    }
    return isRunning;
}
final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;
    private volatile AtomicInteger callsPerHost = new AtomicInteger(0);
    AsyncCall(Callback responseCallback) {
        super("OkHttp %s", redactedUrl());
        this.responseCallback = responseCallback;
    }
    AtomicInteger callsPerHost() {
        return callsPerHost;
    }
    void reuseCallsPerHostFrom(AsyncCall other) {
        this.callsPerHost = other.callsPerHost;
    }
    String host() {
        return originalRequest.url().host();
    }
    Request request() {
        return originalRequest;
    }
    RealCall get() {
        return RealCall.this;
    }
    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!
            }
        }
    }
    @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) {
                Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
            } else {
                responseCallback.onFailure(RealCall.this, e);
            }
        } finally {
            // 每一個端口請求計數減1
            client.dispatcher().finished(this);
        }
    }
}
複製代碼

若是調用了enqueue發送網絡請求,那麼最終會在線程池中執行AsyncCall的execute方法,其內部實現與同步執行基本相似,注意最後會在子線程中直接調用onResponse,所以咱們不能在onResponse裏面直接更新UI。咱們能夠寫一個WrapCall將Call進行包裝這樣就能實現回調在主線程了,代碼以下

class WrapCall(private val call: Call) : Call by call {
    override fun enqueue(responseCallback: Callback) {
        call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                handler.post {
                    responseCallback.onFailure(call, e)
                }
            }
            override fun onResponse(call: Call, response: Response) {
                handler.post {
                    responseCallback.onResponse(call, response)
                }
            }
        })
    }
    companion object {
        private val handler = Handler(Looper.getMainLooper())
    }
}
// 外界使用,只要包裝下
val call = WrapCall(client.newCall(request))
call.enqueue(object : Callback {
    override fun onFailure(call: Call, e: IOException) {
        Log.d(TAG, "錯誤: " + e.message)
    }
    override fun onResponse(call: Call, response: Response) {
        if (response.isSuccessful) {
            Log.d(TAG, "請求成功: ${Looper.myLooper() === Looper.getMainLooper()}" + response.body()!!.string())
        } else {
            Log.d(TAG, "請求失敗: ${Looper.myLooper() === Looper.getMainLooper()}" + response.message())
        }
    }
})
複製代碼

源碼分析到這網絡流程基本已經清晰,下面再來看看OkHttp的鏈接複用。

7、鏈接複用

鏈接池的具體實現是RealConnectionPool,每次在ConnectInterceptor的intercepte方法都會嘗試着先從鏈接池中取出一個鏈接,取不到知足條件的纔會新建一個鏈接

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));
    // 最大空閒鏈接數 默認5個
    private final int maxIdleConnections;
    // 最大保存存活的空閒鏈接時間 默認5分鐘
    private final long keepAliveDurationNs;
    // 當向鏈接池中加入一個鏈接後會執行清理操做,內部會尋找空閒時間最長的鏈接,若是其空閒時間
    // 已經超過了最長時間就會將其關閉,否則就等待指定時間
    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) {
                    }
                }
            }
        }
    };
    // 雙端隊列保存當前OkHttpClient的全部鏈接
    private final Deque<RealConnection> connections = new ArrayDeque<>();
    // 記錄了失敗的路由
    final RouteDatabase routeDatabase = new RouteDatabase();
    // 清理線程是否正在執行
    boolean cleanupRunning;
    // 首先建立了一個最大空閒鏈接爲5,最大保存存活時間5分鐘的鏈接池
    public RealConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
        this.maxIdleConnections = maxIdleConnections;
        this.keepAliveDurationNs = timeUnit.toNanos(keepAliveDuration);
        if (keepAliveDuration <= 0) {
            throw new IllegalArgumentException("keepAliveDuration <= 0: " + keepAliveDuration);
        }
    }
    // 獲取空閒鏈接數量
    public synchronized int idleConnectionCount() {
        int total = 0;
        for (RealConnection connection : connections) {
            if (connection.transmitters.isEmpty()) total++;
        }
        return total;
    }
    // 總共的鏈接數
    public synchronized int connectionCount() {
        return connections.size();
    }
    // Transmitter調用該方法獲取鏈接,內部判斷若是鏈接池有鏈接知足條件就返回true,否則返回false
    boolean transmitterAcquirePooledConnection(Address address, Transmitter transmitter, @Nullable List<Route> routes, boolean requireMultiplexed) {
        assert (Thread.holdsLock(this));
        for (RealConnection connection : connections) {
            if (requireMultiplexed && !connection.isMultiplexed()) continue;
            if (!connection.isEligible(address, routes)) continue;
            transmitter.acquireConnectionNoEvents(connection);
            return true;
        }
        return false;
    }

    // 將一個新建的鏈接放入到鏈接池中
    void put(RealConnection connection) {
        assert (Thread.holdsLock(this));
        // 若是清理線程還沒運行就開始運行
        if (!cleanupRunning) {
            cleanupRunning = true;
            executor.execute(cleanupRunnable);
        }
        // 再將鏈接放入雙端隊列中去
        connections.add(connection);
    }

    // 當一個鏈接從執行中變成了空閒時調用,該方法會喚醒清理現場
    boolean connectionBecameIdle(RealConnection connection) {
        assert (Thread.holdsLock(this));
        if (connection.noNewExchanges || maxIdleConnections == 0) {
            connections.remove(connection);
            return true;
        } else {
            notifyAll(); // Awake the cleanup thread: we may have exceeded the idle connection limit.
            return false;
        }
    }

    // 關閉全部的鏈接
    public void evictAll() {
        List<RealConnection> evictedConnections = new ArrayList<>();
        synchronized (this) {
            for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) {
                RealConnection connection = i.next();
                if (connection.transmitters.isEmpty()) {
                    connection.noNewExchanges = true;
                    evictedConnections.add(connection);
                    i.remove();
                }
            }
        }
        for (RealConnection connection : evictedConnections) {
            closeQuietly(connection.socket());
        }
    }
    // 若是能夠清理的話就關閉Socket返回0,否則返回須要等待的時間
    long cleanup(long now) {
        int inUseConnectionCount = 0;
        int idleConnectionCount = 0;
        RealConnection longestIdleConnection = null;
        long longestIdleDurationNs = Long.MIN_VALUE;
        synchronized (this) {
            for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) {
                RealConnection connection = i.next();
                if (pruneAndGetAllocationCount(connection, now) > 0) {
                    inUseConnectionCount++;
                    continue;
                }
                idleConnectionCount++;
                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) {
                return keepAliveDurationNs - longestIdleDurationNs;
            } else if (inUseConnectionCount > 0) {
                return keepAliveDurationNs;
            } else {
                cleanupRunning = false;
                return -1;
            }
        }
        closeQuietly(longestIdleConnection.socket());
        return 0;
    }
    private int pruneAndGetAllocationCount(RealConnection connection, long now) {
        // 對於Http1.1這個List最多也只有一個元素
        List<Reference<Transmitter>> references = connection.transmitters;
        for (int i = 0; i < references.size(); ) {
            Reference<Transmitter> reference = references.get(i);
            if (reference.get() != null) {
                i++;
                continue;
            }
            // 發現一個泄露的transmitter,這是一個應用程序的bug
            TransmitterReference transmitterRef = (TransmitterReference) reference;
            String message = "A connection to " + connection.route().address().url()
                    + " was leaked. Did you forget to close a response body?";
            Platform.get().logCloseableLeak(message, transmitterRef.callStackTrace);
            references.remove(i);
            connection.noNewExchanges = true; eviction.
            if (references.isEmpty()) {
                connection.idleAtNanos = now - keepAliveDurationNs;
                return 0;
            }
        }
        return references.size();
    }

    // 鏈接失敗時調用將失敗的Route放入到RouteDatabase中
    public void connectFailed(Route failedRoute, IOException failure) {
        // Tell the proxy selector when we fail to connect on a fresh connection.
        if (failedRoute.proxy().type() != Proxy.Type.DIRECT) {
            Address address = failedRoute.address();
            address.proxySelector().connectFailed(
                    address.url().uri(), failedRoute.proxy().address(), failure);
        }
        routeDatabase.failed(failedRoute);
    }
}
複製代碼

8、總結

不論是同步請求仍是異步請求內部都是通過從上到下5個攔截器才能發起請求,獲取到響應後還會通過這5個攔截器而後纔將結果返回到外界,典型的責任鏈模式與Android事件分發差很少

  1. RetryAndFollowUpInterceptor 用於錯誤重試,以及重定向
  2. BridgeInterceptor 用於添加請求頭(User-Agent、Connection等等),收到響應的時候可能會進行GZip解壓
  3. CacheInterceptor 進行緩存管理,默認不帶緩存,若是須要緩存能夠給OkHttpClient設置cache屬性,可使用OkHttp內置的Cache類
  4. ConnectInterceptor 進行鏈接,首先從鏈接池中取出能夠複用的鏈接,取不到就新建一個而後經過InetAddress獲取到域名對於的IP地址,而後建立Socket與服務端進行鏈接,鏈接成功後若是是Https請求還會進行握手驗證證書操做
  5. CallServerInterceptor 用於真正的發起請求,從Socket獲取的輸出流寫入請求數據,從輸入流中讀取到響應數據
相關文章
相關標籤/搜索