zoukankan      html  css  js  c++  java
  • 开源框架源码解析系列(1)——进入OkHttp的世界

    以前曾经写过一篇关于Okhttp的使用的文章深入解析OkHttp3,通过这篇文章可以了解OkHttp的各种基本用法,光会使用并不算好汉,我们还要深入理解源码,学习优秀的设计思想,本篇我就带大家一起分析源码,基于Okhttp 3.10.0版本。

    1.请求部分源码解析
    1.1 回顾请求的基本用法
    1.1.1 发送同步请求

    Request request = new Request.Builder().url(url).build();
    try {
    //同步请求
    Call call = mOkHttpClient.newCall(request);
    Response response = call.execute();
    String json = response.body().string();
    Log.d(TAG, json);

    } catch (IOException e) {
    e.printStackTrace();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    1.1.2 发送异步请求

    //异步请求
    Call call = mOkHttpClient.newCall(request);
    call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
    Log.d(TAG, "onFailure:" + e.getMessage());
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
    String json = response.body().string();
    Log.d(TAG, json);
    }
    });
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    1.2 同步请求源码分析
    首先,我们要理解,无论是同步请求还是异步请求,我们都需要先编写以下代码:

    OkHttpClient mOkHttpClient = new OkHttpClient();
    Request request = new Request.Builder().url(url).build();
    Call call = mOkHttpClient.newCall(request);
    1
    2
    3
    Call是请求的关键对象,是通过调用Call的execute方法之后,就会进入请求的逻辑

    Response response = call.execute();
    1
    1.2.1 OkHttpClient# newCall

    @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
    }
    1
    2
    3
    我们可以看到OkHttpClient# newCall会调用RealCall.newRealCall方法

    1.2.2 RealCall # newRealCall

    static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
    }
    1
    2
    3
    4
    5
    6
    查看一下构造函数

    private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
    }
    1
    2
    3
    4
    5
    6
    RealCall的创建过程中会持有OkHttpClient,请求的 Request还有创建了一个拦截器RetryAndFollowUpInterceptor(这个后面会详细说明),同时创建eventListener 。

    1.2.3 Call# execute()
    创建好Call之后,调用execute()方法就开始了请求的流程,Call是一个借口,所以我们要查看它的实现类RealCall。

    1.2.4 RealCall# execute()

    @Override public Response execute() throws IOException {
    synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    try {
    client.dispatcher().executed(this);
    Response result = getResponseWithInterceptorChain();
    if (result == null) throw new IOException("Canceled");
    return result;
    } catch (IOException e) {
    eventListener.callFailed(this, e);
    throw e;
    } finally {
    client.dispatcher().finished(this);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    这里重点在于如下两句

    client.dispatcher().executed(this);
    Response result = getResponseWithInterceptorChain();
    1
    2
    调用OkHttpClient持有的Dispatcher对象执行call,Dispatcher是非常重要的一环,后面详细介绍。

    1.2.5 Dispatcher# execute()

    synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
    }
    1
    2
    3
    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
    1
    将同步请求的RealCall 添加到同步的队列中。

    1.2.6 RealCall# getResponseWithInterceptorChain()
    通过RealCall# getResponseWithInterceptorChain()方法就可以获取请求返回的Response,返回到调用者

    Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    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, null, null, null, 0,
    originalRequest, this, eventListener, client.connectTimeoutMillis(),
    client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    这里主要是一系列拦截器的添加操作,然后调用Interceptor.Chain的proceed方法去执行请求

    chain.proceed(originalRequest)
    1
    拦截器又是另一个非常重要的环节,后面重点提到。

    1.2.7总结同步请求
    同步请求逻辑相对简单,通过Call# execute()最终会调用 RealCall# execute(),然后通过分发器Dispatcher将任务添加到同步队列中,然后通过一系列拦截器操作后进行请求,最后返回Response,全程都在主线程中运行,是阻塞式的。

    1.3 异步请求源码分析
    1.3.1 Call#enqueue
    异步请求,会调用Call#enqueue方法,因为是异步,所以需要传递一个Callback回调,Call#enqueue中调用了RealCall#enqueue

    1.3.2 RealCall#enqueue

    @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    RealCall#enqueue中同样会调用到Dispatcher中,只是调用enqueue方法,同时new AsyncCall将Callback 包一层.AsyncCall是RealCall的内部类,从中可以获取RealCall的Request等成员。

    1.3.2 Dispatcher#enqueue

    synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    runningAsyncCalls.add(call);
    executorService().execute(call);
    } else {
    readyAsyncCalls.add(call);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
    private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

    /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
    1
    2
    3
    4
    5
    主要做了几件事:
    1.判断正在执行的异步任务队列中任务数是否小于maxRequests,且正在执行的任务的host小于 maxRequestsPerHost,这两个值的大小为:

    private int maxRequests = 64;
    private int maxRequestsPerHost = 5;
    1
    2
    同时满足条件,则将AsyncCall 添加到runningAsyncCalls队列中,runningAsyncCalls是异步任务的队列,否则添加到readyAsyncCalls等待队列中。

    2.调用Dispatcher#executorService方法,获取Android系统提供的线程池

    public synchronized ExecutorService executorService() {
    if (executorService == null) {
    executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
    new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
    }
    1
    2
    3
    4
    5
    6
    7
    **注意:**这里设置线程池的最大容量为 Integer.MAX_VALUE,但其实受限于maxRequests,所以最多容量也就64而已。

    3.通过ExecutorService执行AsyncCall任务,可想而知AsyncCall一定是实现了Runnable接口。

    1.3.3 NamedRunnable#run
    AsyncCall继承自NamedRunnable,所以当AsyncCall任务执行时,会执行NamedRunnable#run

    @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
    execute();
    } finally {
    Thread.currentThread().setName(oldName);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    主要逻辑在execute()方法

    1.3.4 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 {
    eventListener.callFailed(RealCall.this, e);
    responseCallback.onFailure(RealCall.this, e);
    }
    } finally {
    client.dispatcher().finished(this);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    可以看到还是会和同步请求一样,调用getResponseWithInterceptorChain()执行各种拦截器,返回Response,无论是同步还是异步最后都会执行Dispatcher#inished()方法,这个后面会提到。

    1.3.5 总结异步请求

    Call#enqueue会调用到 Dispatcher#enqueue,然后判断是否符合最大请求数maxRequests(64),最大请求Host数maxRequestsPerHost (5),符合条件的添加到异步任务队列runningAsyncCalls,通过线程池执行任务,否则添加到等待队列readyAsyncCalls。

    2 Dispatcher分析
    前面分析同步和异步请求的时候,都提到Dispatcher,我们这里重新总结一下:
    1.维护了3个队列,同步请求执行队列runningSyncCalls,异步请求执行队列runningAsyncCalls,异步请求等待队列readyAsyncCalls,3个队列的添加逻辑前面已经提过。

    /** Ready async calls in the order they'll be run. */
    private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

    /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
    private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

    /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
    1
    2
    3
    4
    5
    6
    7
    8
    2.维护了异步请求的线程池,异步执行任务通过线程池进行任务执行

    public synchronized ExecutorService executorService() {
    if (executorService == null) {
    executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
    new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
    }
    1
    2
    3
    4
    5
    6
    7
    3.RealCall中请求任务执行完后,进行回收,我们知道Call会被封装成RealCall,但无论同步还是异步执行完成后,都会调用以下代码

    finally {
    client.dispatcher().finished(this);
    }
    1
    2
    3
    2.1 Dispatcher#finished
    分为同步和异步的finished,我们先看同步的代码:
    2.1.1 同步finished

    /** Used by {@code Call#execute} to signal completion. */
    void finished(RealCall call) {
    finished(runningSyncCalls, call, false);
    }
    1
    2
    3
    4
    注意这里传入的第三个参数为false

    private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
    if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
    if (promoteCalls) promoteCalls();
    runningCallsCount = runningCallsCount();
    idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
    idleCallback.run();
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    1.首先将队列中call进行移除
    2.如果promoteCalls为true还会调用 promoteCalls()方法
    3.计算runningCallsCount,即为同步和异步执行队列的size总和

    public synchronized int runningCallsCount() {
    return runningAsyncCalls.size() + runningSyncCalls.size();
    }
    1
    2
    3
    4.当runningCallsCount为0时说明已经没有任务了,进行回调

    if (runningCallsCount == 0 && idleCallback != null) {
    idleCallback.run();
    }
    1
    2
    3
    void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
    }
    1
    2
    3
    2.1.2 异步finished
    异步代码如下:

    void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
    }
    1
    2
    3
    和同步的区别是,传入的promoteCalls为true,所以当执行finished时会比同步多执行一个promoteCalls()方法
    Dispatcher#promoteCalls


    private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
    AsyncCall call = i.next();

    if (runningCallsForHost(call) < maxRequestsPerHost) {
    i.remove();
    runningAsyncCalls.add(call);
    executorService().execute(call);
    }

    if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    逻辑很清晰,就是当异步执行队列readyAsyncCalls有空闲位置时,遍历等待队列,将readyAsyncCalls的任务取出加入readyAsyncCalls,然后线程池对任务进行执行。

    3.拦截器解析
    3.1 拦截器执行顺序
    在之前分析同步和异步任务的时候,分析过getResponseWithInterceptorChain()方法执行后就会返回请求结果Response

    Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    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, null, null, null, 0,
    originalRequest, this, eventListener, client.connectTimeoutMillis(),
    client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    1.首先将调用者自定义的拦截器都放入interceptors集合的最前面,然后是分别添加okhttp中必须的几个拦截器,后面我们会一一分析
    2.创建拦截器的链RealInterceptorChain,将interceptors传入

    从上述代码可以看出拦截器调用的先后顺序依次是
    client.interceptors()–>RetryAndFollowUpInterceptor–>BridgeInterceptor–>CacheInterceptor–>ConnectInterceptor–>client.networkInterceptors()–>CallServerInterceptor

    这里使用到了非常经典的设计模式,就是责任链模式,reques自上而下下传递执行,然后Response至下而上返回

    这里3个参数是为 null的

    3.2 RealInterceptorChain#proceed
    @Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
    }
    1
    2
    3
    关键部分代码如下:

    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
    connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
    writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    1
    2
    3
    4
    5
    6
    7
    又创建了一个RealInterceptorChain,然后获取interceptors中第一位的拦截器开始执行,这里index=0。然后就会按照顺序执行各拦截器。

    3.3 RetryAndFollowUpInterceptor
    如果没有自定义拦截器情况下,首先会走到RetryAndFollowUpInterceptor的intercept方法

    @Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Call call = realChain.call();
    EventListener eventListener = realChain.eventListener();

    StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
    createAddress(request.url()), call, eventListener, callStackTrace);
    this.streamAllocation = streamAllocation;

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

    Response response;
    boolean releaseConnection = true;
    try {
    response = realChain.proceed(request, streamAllocation, null, null);
    releaseConnection = false;
    } catch (RouteException e) {
    //省略
    } catch (IOException e) {
    //省略
    } finally {
    // We're throwing an unchecked exception. Release any resources.
    if (releaseConnection) {
    streamAllocation.streamFailed(null);
    streamAllocation.release();
    }
    }

    // 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, streamAllocation.route());

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

    closeQuietly(response.body());

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

    if (!sameConnection(response, followUp.url())) {
    streamAllocation.release();
    streamAllocation = new StreamAllocation(client.connectionPool(),
    createAddress(followUp.url()), call, eventListener, callStackTrace);
    this.streamAllocation = streamAllocation;
    } 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;
    }
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    1.创建StreamAllocation

    StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
    createAddress(request.url()), call, eventListener, callStackTrace);
    this.streamAllocation = streamAllocation;
    1
    2
    3
    主要传入OkHttpClient中的ConnectionPool,还有通过请求request.url()创建出Address对象,主要是HTTP请求中一些SSLSocket,host认证,Dns等

    realChain.proceed
    try {
    response = realChain.proceed(request, streamAllocation, null, null);
    releaseConnection = false;
    }
    1
    2
    3
    4
    realChain执行proceed方法,此时streamAllocation已经有值传入,此时再次进入RealInterceptorChain#proceed方法中

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

    calls++;

    //省略
    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
    connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
    writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    //省略
    return response;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    这里再次进来index已经变为1,然后又再新创建一个RealInterceptorChain,从interceptors中取出下一个拦截器,执行下一个拦截器的逻辑

    **总结一下:**这里责任链模式,每一个拦截器执行时都会创建一个拦截器链RealInterceptorChain,index也会随之增加1,这样在 interceptors.get(index)中就会取出下一个拦截器,一直向下执行到没有拦截器为止,同时每一个拦截的Response是下一个拦截器执行的返回的结果

    RetryAndFollowUpInterceptor最重要的是创建了StreamAllocation

    3.4 BridgeInterceptor拦截器
    BridgeInterceptor#intercept

    @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();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    BridgeInterceptor拦截器的作用主要是添加一些网络请求的必备参数,例如Content-Type,Content-Length,Host,ConnectionAccept-Encoding,Cookie,User-Agent等,如果有使用gzip的话,还会进行gzip的处理

    3.5 CacheInterceptor拦截器
    3.5.1 CacheInterceptor#intercept
    @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 we're forbidden from using the network and the cache is insufficient, fail.
    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();
    }

    // If we don't need the network, we're done.
    if (networkRequest == null) {
    return cacheResponse.newBuilder()
    .cacheResponse(stripBody(cacheResponse))
    .build();
    }

    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)) {
    // 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;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    1.先从cache中以chain.request()为key获取缓存的Response,这里的request就是外部调用时创建的,这里的cache是InternalCache,实现类为okhttp3.Cache,查看get方法

    3.5.2 okhttp3.Cache#get
    @Nullable
    Response get(Request request) {
    String key = key(request.url());

    Snapshot snapshot;
    try {
    snapshot = this.cache.get(key);
    if (snapshot == null) {
    return null;
    }
    } catch (IOException var7) {
    return null;
    }

    Cache.Entry entry;
    try {
    entry = new Cache.Entry(snapshot.getSource(0));
    } catch (IOException var6) {
    Util.closeQuietly(snapshot);
    return null;
    }

    Response response = entry.response(snapshot);
    if (!entry.matches(request, response)) {
    Util.closeQuietly(response.body());
    return null;
    } else {
    return response;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    1.根据请求的url,进行计算获得一个key
    2.在内部cache中通过key看有没保存的快照Snapshot。这里cache是采用了DiskLruCache的算法
    3.如果Snapshot不为空,通过Snapshot创建出Cache.Entry,查看一下Cache.Entry的组成

    其实就是存储了一些请求返回的信息

    4.通过entry.response方法获取缓存中的Response

    public Response response(Snapshot snapshot) {
    String contentType = this.responseHeaders.get("Content-Type");
    String contentLength = this.responseHeaders.get("Content-Length");
    Request cacheRequest = (new okhttp3.Request.Builder()).url(this.url).method(this.requestMethod, (RequestBody)null).headers(this.varyHeaders).build();
    return (new okhttp3.Response.Builder()).request(cacheRequest).protocol(this.protocol).code(this.code).message(this.message).headers(this.responseHeaders).body(new Cache.CacheResponseBody(snapshot, contentType, contentLength)).handshake(this.handshake).sentRequestAtMillis(this.sentRequestMillis).receivedResponseAtMillis(this.receivedResponseMillis).build();
    }
    1
    2
    3
    4
    5
    6
    通过缓存得参数构造Request ,然后通过Request再创建出Response
    5.校验缓存中的请求和相应是否和传入的Request所关联的一致

    entry.matches(request, response)
    1
    6.将请求链chain中的request和缓存Response构造出一个CacheStrategy

    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
    1
    3.5.3 CacheStrategy#Factory方法

    其实就是从缓存的cacheResponse中取出一些值进行赋值

    3.5.4 CacheStrategy.Factory#get方法
    public CacheStrategy get() {
    CacheStrategy candidate = getCandidate();

    if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {
    // We're forbidden from using the network and the cache is insufficient.
    return new CacheStrategy(null, null);
    }

    return candidate;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    主要逻辑在getCandidate方法中

    CacheStrategy#getCandidate
    private CacheStrategy getCandidate() {
    // No cached response.
    if (cacheResponse == null) {
    return new CacheStrategy(request, null);
    }

    // Drop the cached response if it's missing a required handshake.
    if (request.isHttps() && cacheResponse.handshake() == null) {
    return new CacheStrategy(request, null);
    }

    // If this response shouldn't have been stored, it should never be used
    // as a response source. This check should be redundant as long as the
    // persistence store is well-behaved and the rules are constant.
    if (!isCacheable(cacheResponse, request)) {
    return new CacheStrategy(request, null);
    }

    CacheControl requestCaching = request.cacheControl();
    if (requestCaching.noCache() || hasConditions(request)) {
    return new CacheStrategy(request, null);
    }

    CacheControl responseCaching = cacheResponse.cacheControl();
    if (responseCaching.immutable()) {
    return new CacheStrategy(null, cacheResponse);
    }

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

    // Find a condition to add to the request. If the condition is satisfied, the response body
    // will not be transmitted.
    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); // No condition! Make a regular request.
    }

    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);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    getCandidate方法决定CacheStrategy的构成,一般会有如下一些情况:
    noCache :不使用缓存,全部走网络
    noStore : 不使用缓存,也不存储缓存
    onlyIfCached : 只使用缓存
    maxAge :设置最大失效时间,失效则不使用
    maxStale :设置最大失效时间,失效则不使用
    minFresh :设置最小有效时间,失效则不使用
    FORCE_NETWORK : 强制走网络
    FORCE_CACHE :强制走缓存

    可以发现CacheStrategy中cacheResponse为null空有几种情况
    1)没有缓存的response
    2)如果这个请求是https的,但上次缓存的cacheResponse没有TLS handshake
    3.通过isCacheable判断,一些请求返回值不符合要求的不缓存,还有就是请求头中有配置no-store参数时
    4.请求头中声明了“no-cache”,或者“If-Modified-Since”,“If-None-Match”(服务器缓存)
    5.请求头中没有添加任何条件时候

    继续看 get()方法

    if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {
    // We're forbidden from using the network and the cache is insufficient.
    return new CacheStrategy(null, null);
    }
    1
    2
    3
    4
    如果外部设置了onlyIfCached(只读缓存),但缓存又无效,那就构造的CacheStrategy中既没有request也没有request

    3.5.5 再次回到 CacheInterceptor#intercept
    // If we're forbidden from using the network and the cache is insufficient, fail.
    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();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    1.如果设置了only-if-cached,只读缓存,但又没有缓存的Response,那就返回504

    // If we don't need the network, we're done.
    if (networkRequest == null) {
    return cacheResponse.newBuilder()
    .cacheResponse(stripBody(cacheResponse))
    .build();
    }
    1
    2
    3
    4
    5
    6
    2.networkRequest == null这里表示只用缓存,不用网络请求,那就将缓存返回

    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());
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    3.networkRequest !=null,那就调用接下来的拦截器进行请求,返回Response

    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());
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    4.如果旧的cacheResponse不为null,又通过网络请求返回操作码304,则将新的response更新


    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.
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    5.新的请求进行缓存,然后过期缓存进行移除

    3.6 ConnectInterceptor拦截器
    ConnectInterceptor#intercept

    @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");
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    RealConnection connection = streamAllocation.connection();

    return realChain.proceed(request, streamAllocation, httpCodec, connection);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    从链中获取出StreamAllocation,通过streamAllocation.newStream方法返回一个HttpCodec,HttpCodec的作用是对请求进行编码,然后对响应进行解码

    3.6.1 StreamAllocation#newStream
    public HttpCodec newStream(
    OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
    int connectTimeout = chain.connectTimeoutMillis();
    int readTimeout = chain.readTimeoutMillis();
    int writeTimeout = chain.writeTimeoutMillis();
    int pingIntervalMillis = client.pingIntervalMillis();
    boolean connectionRetryEnabled = client.retryOnConnectionFailure();

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    通过findHealthyConnection方法创建一个RealConnection,此类负责https连接的主要工作,RealConnection#newCodec方法可以创建出HttpCodec,并返回。

    3.6.2 StreamAllocation#findHealthyConnection
    通过findConnection方法创建RealConnection,如果这个RealConnection是全新的连接,就跳过连接健康检查,如果是之前已经连接过的RealConnection,则判断是不是一个健康的连接,如果否的话就将其从连接池connectionPool中进行回收。接下来看findConnection方法做了什么

    3.6.3 StreamAllocation#findConnection
    ......
    if (result == null) {
    // Attempt to get a connection from the pool.
    Internal.instance.get(connectionPool, address, this, null);
    if (connection != null) {
    foundPooledConnection = true;
    result = connection;
    } else {
    selectedRoute = route;
    }
    }
    ......
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Internal.instance.get方法从连接池中获取是否有复用的连接,Internal是一个接口,它的实现在OkHttpClient的内部类中

    1.OkHttpClient.Internal.instance#get

    @Override public RealConnection get(ConnectionPool pool, Address address,
    StreamAllocation streamAllocation, Route route) {
    return pool.get(address, streamAllocation, route);
    }
    1
    2
    3
    4
    2.ConnectionPool#get

    @Nullable RealConnection get(Address address, StreamAllocation streamAllocation, Route route) {
    assert (Thread.holdsLock(this));
    for (RealConnection connection : connections) {
    if (connection.isEligible(address, route)) {
    streamAllocation.acquire(connection, true);
    return connection;
    }
    }
    return null;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    在连接池中找出能匹配Address 的连接,注意这里的route传进来为null,connection.isEligible方法判断连接池中connection是否可复用,主要通过判断请求连接的host是否一致,具体逻辑在RealConnection#isEligible中
    3.RealConnection#isEligible

    public boolean isEligible(Address address, @Nullable Route route) {
    // If this connection is not accepting new streams, we're done.
    if (allocations.size() >= allocationLimit || noNewStreams) return false;

    // If the non-host fields of the address don't overlap, we're done.
    if (!Internal.instance.equalsNonHost(this.route.address(), address)) return false;

    // If the host exactly matches, we're done: this connection can carry the address.
    if (address.url().host().equals(this.route().address().url().host())) {
    return true; // This connection is a perfect match.
    }

    // At this point we don't have a hostname match. But we still be able to carry the request if
    // our connection coalescing requirements are met. See also:
    // https://hpbn.co/optimizing-application-delivery/#eliminate-domain-sharding
    // https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/

    // 1. This connection must be HTTP/2.
    if (http2Connection == null) return false;

    // 2. The routes must share an IP address. This requires us to have a DNS address for both
    // hosts, which only happens after route planning. We can't coalesce connections that use a
    // proxy, since proxies don't tell us the origin server's IP address.
    if (route == null) return false;
    if (route.proxy().type() != Proxy.Type.DIRECT) return false;
    if (this.route.proxy().type() != Proxy.Type.DIRECT) return false;
    if (!this.route.socketAddress().equals(route.socketAddress())) return false;

    // 3. This connection's server certificate's must cover the new host.
    if (route.address().hostnameVerifier() != OkHostnameVerifier.INSTANCE) return false;
    if (!supportsUrl(address.url())) return false;

    // 4. Certificate pinning must match the host.
    try {
    address.certificatePinner().check(address.url().host(), handshake().peerCertificates());
    } catch (SSLPeerUnverifiedException e) {
    return false;
    }

    return true; // The caller's address can be carried by this connection.
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    通过streamAllocation.acquire(connection, true),将connection和StreamAllocation相关联

    4.StreamAllocation#acquire

    public void acquire(RealConnection connection, boolean reportedAcquired) {
    assert (Thread.holdsLock(connectionPool));
    if (this.connection != null) throw new IllegalStateException();

    this.connection = connection;
    this.reportedAcquired = reportedAcquired;
    connection.allocations.add(new StreamAllocationReference(this, callStackTrace));
    }
    1
    2
    3
    4
    5
    6
    7
    8
    在这里将connection赋值给了StreamAllocation,然后connection有一个集合存放与其关联的StreamAllocation,这里StreamAllocationReference是一个弱引用。

    3.6.4 再次回到ConnectInterceptor#intercept
    RealConnection connection = streamAllocation.connection();
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
    1
    2
    通过streamAllocation获取出connection,继续传递给下一个拦截器

    4.CallServerInterceptor 拦截器
    这个是Okhttp中自带的最后一个拦截器

    4.1CallServerInterceptor#intercept
    @Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    HttpCodec httpCodec = realChain.httpStream();
    StreamAllocation streamAllocation = realChain.streamAllocation();
    RealConnection connection = (RealConnection) realChain.connection();
    Request request = realChain.request();

    long sentRequestMillis = System.currentTimeMillis();

    realChain.eventListener().requestHeadersStart(realChain.call());
    httpCodec.writeRequestHeaders(request);
    realChain.eventListener().requestHeadersEnd(realChain.call(), request);

    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"))) {
    httpCodec.flushRequest();
    realChain.eventListener().responseHeadersStart(realChain.call());
    responseBuilder = httpCodec.readResponseHeaders(true);
    }

    if (responseBuilder == null) {
    // Write the request body if the "Expect: 100-continue" expectation was met.
    realChain.eventListener().requestBodyStart(realChain.call());
    long contentLength = request.body().contentLength();
    CountingSink requestBodyOut =
    new CountingSink(httpCodec.createRequestBody(request, contentLength));
    BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);

    request.body().writeTo(bufferedRequestBody);
    bufferedRequestBody.close();
    realChain.eventListener()
    .requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
    } 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();

    if (responseBuilder == null) {
    realChain.eventListener().responseHeadersStart(realChain.call());
    responseBuilder = httpCodec.readResponseHeaders(false);
    }

    Response response = responseBuilder
    .request(request)
    .handshake(streamAllocation.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
    responseBuilder = httpCodec.readResponseHeaders(false);

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

    code = response.code();
    }

    realChain.eventListener()
    .responseHeadersEnd(realChain.call(), 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(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;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    这个拦截器主要的任务如下:
    1.写入请求头
    2.写入请求体
    3.读取响应头
    4.读取响应体

    这样所有的Okhttp流程基本分析完毕,再往深入网络连接流这一块能力有限无法进行分析
    ---------------------

  • 相关阅读:
    属性值和引号
    PPT中背景音乐与插入文件中的声音有什么区别?
    C#笔记分享
    为什么《穹顶之下》没有说服我?
    Office 2019安装并激活(最简洁的安装方法)
    【转】获取Sprite的实际Rect
    什么是Cocos2d-x
    【转】最新基于adt-bundle-windows-x86的android开发环境搭建
    在cocos2d-x中使用位图字体
    TexturePacker的使用
  • 原文地址:https://www.cnblogs.com/hyhy904/p/11097332.html
Copyright © 2011-2022 走看看