OkHttp学习(二)-请求流程分析

整体流程

下面这张图很好的说明了OkHttp的网络请求流程,来自于拆轮子系列:拆 OkHttp

OkHttp最简单的使用如下所示:

  OkHttpClient client = new OkHttpClient.Builder().build();
  Request request = new Request.Builder().url("....").build();
  Call call = client.newCall(request);
  call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {

    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {

    }
  });

1. OkHttpClient.Builder

public static final class Builder {
    public Builder() {
        dispatcher = new Dispatcher();
        protocols = DEFAULT_PROTOCOLS;//HTTP_2, Http_1_1
        connectionSpecs = DEFAULT_CONNECTION_SPECS; //MODERN_TLS, CLEARTEXT
        eventListenerFactory = EventListener.factory(EventListener.NONE);
        proxySelector = ProxySelector.getDefault();
        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;
        connectTimeout = 10_000;
        readTimeout = 10_000;
        writeTimeout = 10_000;
        pingInterval = 0;
    }
}
  1. 默认Cache是为空
  2. 默认CookieJar = CookieJar.NO_COOKIES, 即不做cookie管理
  3. 创建一个ConnectionPool(maxIdleConnections: 5, keepAliveDurations: 5, TimeUnit.Minutes)

2. Request.Builder

public static class Builder {
        HttpUrl url;
        String method;
        Headers.Builder headers;
        RequestBody body;
        Object tag;

        //默认请求方法是GET, 默认Headers是空的,后面会再添加
        public Builder() {
            this.method = "GET";
            this.headers = new Headers.Builder();
        }

        //根据传入的url生成一个HttpUrl对象
        public Builder url(String url) {
            if (url == null)
              throw new NullPointerException("url == null");

            //自动将web socket url替换为http的url
            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);
            }

            HttpUrl parsed = HttpUrl.parse(url);
            if (parsed == null)
                throw new IllegalArgumentException("unexpected url: " + url);
            return url(parsed);
        }
        ....
}

  1. 默认Request的body是null
  2. headers也为空

3. OkHttpClient.newCall(Request request)

@Override
public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
}

可以看到,内部实际调用的是RealCall.newCall来生成Call

3.1 RealCall.newRealCall

static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    //默认client.eventListenerFactory返回OkHttpClient.Builder.eventListenerFactory
    //Builder.eventListenerFactory是默认的EventListener.NONE即一个空实现
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
}

3.2 new RealCall

private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}

RealCall内部会创建RetryAndFollowUpInterceptor

4. RealCall.enqueue

@Override
public void enqueue(Callback responseCallback) {
    synchronized (this) {
        if (executed)
            throw new IllegalStateException("Already Executed");
        executed = true;
    }
    // 获取response.body().close()方法执行时的异常stack trace,将获取到的
    // stack trace信息赋予retryAndFollowUpInterceptor
    captureCallStackTrace();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

RealCall.enqueue内部手机调用的Dispatcher.enqueue, 在调用Dispatcher.enqueue之前会创建一个AsyncCall, AsyncCall实际就是一个Runnable

4.1 new AsyncCall

//NamedRunnable继承自Runnable, 实质是在run()方法调用子类的execute()方法,这里即AsyncCall的execute()方法
final class AsyncCall extends NamedRunnable {
  AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
  }
  ...
}

NamedRunnable继承自Runnable, 实质是在run()方法调用子类的execute()方法,这里即AsyncCall的execute()方法

4.2 Dispatcher.enqueue

/*
* 如果一个host的同时请求数量没有达到上限的话,将传入的AsyncCall放入running队列中,并将AsyncCall放入线程池中执行该任务(即调用run()方法,
* 而AsyncCall继承自NamedRunnable, 所以最终会调用execute方法)
* 如果达到上限,则将传入的AsyncCall放入ready队列中
*/
synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
        runningAsyncCalls.add(call);
        executorService().execute(call);
    } else {
        readyAsyncCalls.add(call);
    }
}

如果一个host即服务器的同时请求数量没有达到上限的话,会把新建的任务放入正在运行的队列中,同时在线程池中执行该任务,如果请求数量达到上限,则先将任务放入代运行队列中

4.3 AsyncCall.execute


  @Override
  protected void execute() {
      boolean signalledCallback = false;
      try {
          Response response = getResponseWithInterceptorChain();

          if (retryAndFollowUpInterceptor.isCanceled()) {
              signalledCallback = true;
              responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
          } else {
              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);
          }
      } finally {
          //网络请求结束,将当前AsyncCall从running队列中删除
          //检查ready队列中是否有待处理的请求,有则处理
          client.dispatcher().finished(this);
      }
  }

线程池执行以后会调用Runnable.run方法,同时通过之前4.1可以知道AsyncCall继承自NamedRunnable,最终会调用execute方法

4.4 RealCall.getResponseWithInterceptorChain

Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List<Interceptor> interceptors = new ArrayList<>();
        //如果有自定义的Interceptor, 先添加全部的自定义Interceptor
        interceptors.addAll(client.interceptors());
        //添加RetryAndFollowUpInterceptor
        interceptors.add(retryAndFollowUpInterceptor);
        //client默认的cookieJar是一个空实现既不做cookie管理, 添加BridgeInterceptor
        interceptors.add(new BridgeInterceptor(client.cookieJar()));
        //client默认internalCache = null, 添加CacheInterceptor
        interceptors.add(new CacheInterceptor(client.internalCache()));
        //添加ConnectInterceptor
        interceptors.add(new ConnectInterceptor(client));
        //一般情况下forWebSocket = false, 添加client的networkInterceptors
        if (!forWebSocket) {
            interceptors.addAll(client.networkInterceptors());
        }
        //添加CallServerInterceptor
        interceptors.add(new CallServerInterceptor(forWebSocket));

        //创建RealInterceptorChain,并调用chain.proceed()
        //eventListener是一个空实现
        Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
                originalRequest, this, eventListener, client.readTimeoutMillis());
        return chain.proceed(originalRequest);
    }

依次添加各个Interceptor添加的顺序是:

  1. 用户自定义的Interceptor
  2. 之前创建的RetryAndFollowUpInterceptor
  3. 添加一个新建的BridgeInterceptor
  4. 添加一个新建的CacheInterceptor
  5. 添加一个新建的ConnectInterceptor
  6. 如果不是针对WebSocket, 则再添加自定义的network interceptor
  7. 最后添加新建的CallServerInterceptor

4.5 RealInterceptorChain.proceed

@Override
public Response proceed(Request request) throws IOException {
    //streamAllocation = null, httpCodec = null, connection = null
    return proceed(request, streamAllocation, httpCodec, connection);
}


public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
                          RealConnection connection) throws IOException {
      if (index >= interceptors.size())
        throw new AssertionError();

      calls++;

      if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
          throw new IllegalStateException(...);
      }
      if (this.httpCodec != null && calls > 1) {
          throw new IllegalStateException(...);
      }

      // 依次调用各Interceptor
      RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
              connection, index + 1, request, call, eventListener, readTimeout);
      Interceptor interceptor = interceptors.get(index);
      Response response = interceptor.intercept(next);

      // 确保每个Interceptor都只执行一次proceed
      if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
          throw new IllegalStateException(...);
      }

      // Confirm that the intercepted response isn't null.
      if (response == null) {
          throw new NullPointerException(...);
      }

      if (response.body() == null) {
          throw new IllegalStateException(...);
      }

      return response;
  }

该方法最重要的一点是依次调用各个Interceptorintercept()方法, 调用的顺序为:

  1. 自定义Interceptors
  2. RetryAndFollowUpInterceptor
  3. BridgeInterceptor
  4. CacheInterceptor
  5. ConnectInterceptor
  6. 自定义添加的Network Interceptors
  7. CallServerInterceptor

4.6 RetryAndFollowUpInterceptor.interceptor

Request request = chain.request();
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        //RealCall
        Call call = realChain.call();
        //EventListener的空实现
        EventListener eventListener = realChain.eventListener();

        //新建一个StreamAllocation, 根据OkHttpClient的SSLSocketFactory, HostnameVerifier, Dns, CertificatePinner
        //等属性新建一个Address对象
        //callStackTrace是之前调用RealCall.enqueue时设置的关于Response.body().close()方法的异常栈
        streamAllocation = new StreamAllocation(client.connectionPool(), createAddress(request.url()),
                call, eventListener, callStackTrace);

        int followUpCount = 0;
        Response priorResponse = null;
        while (true) {
            if (canceled) {
                streamAllocation.release();
                throw new IOException("Canceled");
            }

            Response response = null;
            boolean releaseConnection = true;
            try {
                //调用下一个Interceptor, 即BridgeInterceptor的intercept方法
                //NOTE: 要执行完所有Interceptor.intercept以后再去执行之后的代码逻辑
                response = realChain.proceed(request, streamAllocation, null, null);
                releaseConnection = false;
            } catch (RouteException e) {
                if (!recover(e.getLastConnectException(), false, request)) {
                    throw e.getLastConnectException();
                }
                releaseConnection = false;
                continue;
            } catch (IOException e) {
                boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
                if (!recover(e, requestSendStarted, request)) throw e;
                releaseConnection = false;
                continue;
            } finally {
              ....
            }
            ...
        }
    }

NOTE: 所有Interceptor是一个完整的调用链,RetryAndFollowUpInterceptor.intercept是起始处,当所有的Interceptor执行完以后,RetryAndFollowUpInterceptor才会再执行finally以后的代码逻辑

4.7 BridgeInterceptor.interceptor

        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());
        }

        //执行CacheInterceptor.intercept
        Response networkResponse = chain.proceed(requestBuilder.build());

        ....
}

BridgeInterceptor.intercept主要就是根据Request添加一些必要的http请求的header

4.8 CacheInterceptor.interceptor

    @Override
    public Response intercept(Chain chain) throws IOException {
        //默认情况下, cache = null
        Response cacheCandidate = cache != null
                ? cache.get(chain.request())
                : null;

        long now = System.currentTimeMillis();

        //一帮情况下,由于cacheCandidate = null, 所以直接返回一个new CacheStrategy(request, null)
        CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
        Request networkRequest = strategy.networkRequest;
        Response cacheResponse = strategy.cacheResponse;

        if (cache != null) {
            cache.trackResponse(strategy);
        }

        //如果cacheResponse = null, 则调用cacheCandidate的ResponseBody.close()
        if (cacheCandidate != null && cacheResponse == null) {
            closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
        }

        //如果既没有Request也没有Cache Response, 生成一个空body, code = 504的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();
        }

        // 如果Request = null, 但是有缓存的Response, 返回缓存的Response
        if (networkRequest == null) {
            return cacheResponse.newBuilder()
                    .cacheResponse(stripBody(cacheResponse))
                    .build();
        }

        //调用ConnectInterceptor.interceptor()
        Response networkResponse = null;
        try {
            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());
            }
        }

        ...

}

4.9 ConnectInterceptor

    @Override
    public Response intercept(Chain chain) throws IOException {
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        Request request = realChain.request();
        StreamAllocation streamAllocation = realChain.streamAllocation();

        // We need the network to satisfy this request. Possibly for validating a conditional GET.
        boolean doExtensiveHealthChecks = !request.method().equals("GET");
        //创建RealConnection和HttpCodec
        HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
        RealConnection connection = streamAllocation.connection();
        //调用CallServerInterceptor.interceptor
        return realChain.proceed(request, streamAllocation, httpCodec, connection);
    }

4.9.1 StreamAllocation.newStream

  public HttpCodec newStream(
            OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {

        //10000
        int connectTimeout = client.connectTimeoutMillis();
        //10000
        int readTimeout = chain.readTimeoutMillis();
        //10000
        int writeTimeout = client.writeTimeoutMillis();
        //true
        boolean connectionRetryEnabled = client.retryOnConnectionFailure();

        try {
            RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
                    writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);
            HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);

            synchronized (connectionPool) {
                codec = resultCodec;
                return resultCodec;
            }
        } catch (IOException e) {
            throw new RouteException(e);
        }
    }

4.9.2 StreamAllocation.findHealthyConnection

private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
                                                 int writeTimeout, boolean connectionRetryEnabled, boolean doExtensiveHealthChecks)
            throws IOException {

        while (true) {
            RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
                    connectionRetryEnabled);

            // If this is a brand new connection, we can skip the extensive health checks.
            synchronized (connectionPool) {
                if (candidate.successCount == 0) {
                    return candidate;
                }
            }

            // Do a (potentially slow) check to confirm that the pooled connection is still good. If it
            // isn't, take it out of the pool and start again.
            if (!candidate.isHealthy(doExtensiveHealthChecks)) {
                noNewStreams();
                continue;
            }

            return candidate;
        }
    }

4.9.3 StreamAllocation.findConnection


private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
                                          boolean connectionRetryEnabled) throws IOException {
        Route selectedRoute;
        synchronized (connectionPool) {
            if (released)
              throw new IllegalStateException("released");
            if (codec != null)
              throw new IllegalStateException("codec != null");
            if (canceled)
              throw new IOException("Canceled");

            // 如果this.connection已经创建,则直接返回this.connection
            // 但第一次创建时,this.connection = null
            RealConnection allocatedConnection = this.connection;
            if (allocatedConnection != null && !allocatedConnection.noNewStreams) {
                return allocatedConnection;
            }

            //从connectionPool中尝试获取,注意route = null
            Internal.instance.get(connectionPool, address, this, null);
            if (connection != null) {
                return connection;
            }

            selectedRoute = route;
        }

        // If we need a route, make one. This is a blocking operation.
        if (selectedRoute == null) {
            selectedRoute = routeSelector.next();
        }

        RealConnection result;
        synchronized (connectionPool) {
            if (canceled) throw new IOException("Canceled");

            // Now that we have an IP address, make another attempt at getting a connection from the pool.
            // This could match due to connection coalescing.
            Internal.instance.get(connectionPool, address, this, selectedRoute);
            if (connection != null) {
                route = selectedRoute;
                return connection;
            }

            // Create a connection and assign it to this allocation immediately. This makes it possible
            // for an asynchronous cancel() to interrupt the handshake we're about to do.
            route = selectedRoute;
            refusedStreamCount = 0;
            result = new RealConnection(connectionPool, selectedRoute);
            acquire(result);
        }

        // Do TCP + TLS handshakes. This is a blocking operation.
        result.connect(
                connectTimeout, readTimeout, writeTimeout, connectionRetryEnabled, call, eventListener);
        routeDatabase().connected(result.route());

        Socket socket = null;
        synchronized (connectionPool) {
            // Pool the connection.
            Internal.instance.put(connectionPool, result);

            // If another multiplexed connection to the same address was created concurrently, then
            // release this connection and acquire that one.
            if (result.isMultiplexed()) {
                socket = Internal.instance.deduplicate(connectionPool, address, this);
                result = connection;
            }
        }
        closeQuietly(socket);

        return result;
    }

4.10 CallServerInterceptor.intercept

    @Override
    public Response intercept(Chain chain) throws IOException {
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        //HttpCodec是在ConnectInterceptor中创建的
        //如果是https协议则是Http2Codec, 否则是Http1Codec
        HttpCodec httpCodec = realChain.httpStream();
        StreamAllocation streamAllocation = realChain.streamAllocation();
        //RealConnection也是在ConnectInterceptor中创建的
        RealConnection connection = (RealConnection) realChain.connection();
        Request request = realChain.request();

        long sentRequestMillis = System.currentTimeMillis();
        //向已经建立好的连接写入请求头部, 如果是https,还会创建Http2Stream对象
        httpCodec.writeRequestHeaders(request);

        Response.Builder responseBuilder = null;
        if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {

            //如果请求头部中有Except: 100-continue, 在发送body之前先发送一个请求询问server是否愿意接收数据,只有当server
            //返回http/1.1 100 Continue时才继续发送数据,如果服务器没有返回这个,则直接返回server返回的code
            if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
                httpCodec.flushRequest();
                responseBuilder = httpCodec.readResponseHeaders(true);
            }

            if (responseBuilder == null) {
                // Write the request body if the "Expect: 100-continue" expectation was met.
                // 写入Body
                Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
                BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
                request.body().writeTo(bufferedRequestBody);
                bufferedRequestBody.close();
            } else if (!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.
                streamAllocation.noNewStreams();
            }
        }

        httpCodec.finishRequest();

        //读取Response的头部
        if (responseBuilder == null) {
            responseBuilder = httpCodec.readResponseHeaders(false);
        }

        Response response = responseBuilder
                .request(request)
                .handshake(streamAllocation.connection().handshake())
                .sentRequestAtMillis(sentRequestMillis)
                .receivedResponseAtMillis(System.currentTimeMillis())
                .build();

        int code = response.code();
        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(httpCodec.openResponseBody(response))
                    .build();
        }

        if ("close".equalsIgnoreCase(response.request().header("Connection"))
                || "close".equalsIgnoreCase(response.header("Connection"))) {
            streamAllocation.noNewStreams();
        }

        if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
            throw new ProtocolException(
                    "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
        }

        return response;
    }


4.11 ConnectIntercptor.intercept

直接向上返回了CallServerInterceptor得到的Response

4.12 CacheInterceptor.intercept

    @Override
    public Response intercept(Chain chain) throws IOException {

        ...

        //调用ConnectInterceptor.interceptor()
        Response networkResponse = null;
        try {
            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)) {
                //将response放入缓存
                CacheRequest cacheRequest = cache.put(response);
                return cacheWritingResponse(cacheRequest, response);
            }
            //如果method是post, put, patch, delete, move,则移除缓存
            if (HttpMethod.invalidatesCache(networkRequest.method())) {
                try {
                    cache.remove(networkRequest);
                } catch (IOException ignored) {
                    // The cache cannot be written.
                }
            }
        }

        return response;
    }

4.13 BridgeInterceptor.intercept

@Override
public Response intercept(Chain chain) throws IOException {

    ...
    Response networkResponse = chain.proceed(requestBuilder.build());
    //处理Cookie
    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

    Response.Builder responseBuilder = networkResponse.newBuilder()
                .request(userRequest);

    //如果含有Content-Encoding:gzip,即内容是以gzip压缩过的,则解压缩,并移除
    //头部中的Content-Encoding和Content-Length
    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);
        responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));
    }

    return responseBuilder.build();
}

4.14 RetryAndFollowUpInterceptor.intercept


    @Override
    public Response intercept(Chain chain) throws IOException {

        ....
        // 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();
            }
            //查看是否有重定向的响应,有则构建一个新的请求
            Request followUp = followUpRequest(response);

            if (followUp == null) {
                if (!forWebSocket) {
                    streamAllocation.release();
                }
                return response;
            }

            closeQuietly(response.body());
            //最多重试20次
            if (++followUpCount > MAX_FOLLOW_UPS) {
                streamAllocation.release();
                throw new ProtocolException("Too many follow-up requests: " + followUpCount);
            }

            if (followUp.body() instanceof UnrepeatableRequestBody) {
                streamAllocation.release();
                throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
            }
            //检查新请求的服务器地址与老地址是否相同,不相同则回收旧的StramAllocation的内存,如果相同
            //则复用之前的Connection
            if (!sameConnection(response, followUp.url())) {
                streamAllocation.release();
                streamAllocation = new StreamAllocation(client.connectionPool(),
                        createAddress(followUp.url()), call, eventListener, callStackTrace);
            } else if (streamAllocation.codec() != null) {
                throw new IllegalStateException("Closing the body of " + response
                        + " didn't close its backing stream. Bad interceptor?");
            }

            request = followUp;
            priorResponse = response;
    }

推荐阅读更多精彩内容