ok3

一、前言

一直以来都想找个时间看看OKHTTP的源码,最近抽空研究了下,以此记录下对OKHTTP源码的研究成果,当然,网上有很多关于写的很牛逼的博客。我就不和他们比了,谨以此记录一下我的心路历程。 
说明:这篇博客是以OKHTTP3.3.1为研究对象,高版本的我也大概看了一下,改动还是有点大的,这里只讲3.3.1版本的。我这里对OKHTTP3.3.1的流程、框架进行梳理。


二、概述

OKHTTP3.3.1版本,主要的几个核心类为:

类名 描述 类比说明
OkHttpClient 主要涉及OKHTTP内部一些类的初始化,和参数的设置。用户可以拿到OKHTTP的引用进行设置一些用户网络访问的一些参数。 类比于一个咖啡厅的服务员,接受用户请求,自己不做处理,而是分发给下一层。
ReallCall 处理用户请求,并返回响应结果给用户的类 类比于咖啡机的按键,接受服务员请求,给内部机器处理,然后自己得到结果给服务员
Dispatcher 请求事件处理分发类,将请求事件分为正在执行的请求(runningAsyncCalls)和 准备执行的请求(readyAsyncCalls) 咖啡机内部机器接收到指令后,进行执行指令操作,一次只能执行6个指令(runningAsyncCalls),多余的等待(readyAsyncCalls)
ApplicationInterceptorChain 拦截器链,存在于Realcall内部, 咖啡机内部的一条监控程序(分析程序),贯穿整个生产过程,在机器运行过程中,通过拦截,获取拦截处的样品,分析并将结果返还给用户
HttpEngine 网络请求引擎,负责网络连接任务的分发,请求响应数据打包压缩给上层 咖啡机内部将上层过来的指令分发给具体的生产咖啡的执行模块,而自己负责给生产完成的咖啡做最后的处理(加糖、加奶),并装入纸杯中
StreamAllocation 发送socket连接远端服务器请求并返回一个HttpSteam给上层  
RealConnection socket连接服务器实际执行的类,该类将一些必要的数据参数传递给底层,然后进行相应的操作  

说明:以上这些类是我个人认为是OKHTTP的核心类。其中说明下,在高版本的OKHTTP源码中,设计者已对代码进行了一些改动,其中HttpEngine类被分解,ApplicationInterceptorChain类被移除,取而代之的是多个内置的拦截器,层层执行,并将最终结果返回给调用者。


三、源码流程讲解

前置:整个流程讲解围绕我们使用方式为入口。

3.1 OKHTTP的使用方式

说明:OKHTTP有两种调用方式:1、同步调用 2、异步调用

3.1.1 同步调用方式
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
                .url("http://www.baidu.com")
                .build();
 client.newCall(request).execute();
  • 1
  • 2
  • 3
  • 4
  • 5
3.1.2 异步调用方式
OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url("http://www.baidu.com")
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

说明:同步请求为当前线程只能执行一个请求,而异步则不同,由于其内部有一个线程池执行请求,所以异步可以执行多个。同步和异步单条请求内部的实现方式都一样,下面就围绕异步请求来讲。

3.2 OKHTTP异步请求流程讲解
3.2.1 client.newCall(request)
/**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
    return new RealCall(this, request);
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

说明:该方法实际上是创建一个RealCall的实例,并将Request的的实例作为参数传入RealCall类中

3.2.2 realcall.enqueue(CallBack callback)
//异步请求
  void enqueue(Callback responseCallback, boolean forWebSocket) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //核心方法,两个操作。1、dispatcher.enqueue()分发请求,并执行 2、用户传入的request对象转换成AsyncCall对象
    client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我们首先看下client.dispatcher().enqueue()这个方法的内部执行

//假如正在执行的异步回调小于maxRequests 64 对单个host请求数小于5,则将新的回调添加到runningAsyncCalls,否则将该新的请求添加到异步执行的队列中
  synchronized void enqueue(RealCall.AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
     //runningAsyncCalls 正在执行的异步请求队列
      runningAsyncCalls.add(call);
      //线程池执行线程,实际调用的是AsyncCall中的execute()方法
      executorService().execute(call);  //executorService 线程池
    } else { 
     //readyAsyncCalls准备执行的异步请求队列
      readyAsyncCalls.add(call);
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

再看new AsyncCall(responseCallback, forWebSocket)

final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;
    private final boolean forWebSocket;

    private AsyncCall(Callback responseCallback, boolean forWebSocket) {
      super("OkHttp %s", redactedUrl().toString());
      this.responseCallback = responseCallback;
      this.forWebSocket = forWebSocket;
    }
    ----此处代码省略----
    //网络请求的入口,diapather线程池执行最终调用的是该方法
    @Override 
    protected void execute() {
      boolean signalledCallback = false;
      try {
      //获得网络请求及拦截链返回的响应数据
        Response response = getResponseWithInterceptorChain(forWebSocket);
        if (canceled) {
          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(Platform.INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        //每次执行完必定要走这里,该方法实际上是循环执行网络请求,类似于for循环,这种写法非常有意思。
        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
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

再看下client.dispatcher().finished(this)这个方法

 /** Used by {@code AsyncCall#run} to signal completion. */
  synchronized void finished(RealCall.AsyncCall call) {
    if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
    promoteCalls();
  }
  private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
    //轮询待执行的请求,并将待执行的请求加入到正在执行的队列中,然后执行线程
      for (Iterator<RealCall.AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      RealCall.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
  • 19
  • 20
  • 21

到此,我们一个请求,从发送到执行再到返回数据,这整个流程就这样说完了。咳咳!这只是冰山一角,下面我们就深入它的内部执行。上面说到OKHTTP的同步和异步调用本质的内部实现方法是一样的,都执行了Response response = getResponseWithInterceptorChain(forWebSocket)这个方法,下面我们看下和这个方法的内部执行。

private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
    return chain.proceed(originalRequest);
  }
  • 1
  • 2
  • 3
  • 4

说明:ApplicationInterceptorChain类是RealCall的内部类,维护整个Application的拦截器链,最后调用chain.proceed(originalRequest)方法,下面看下该方法的具体实现代码如下:

class ApplicationInterceptorChain implements Interceptor.Chain {
    private final int index;
    private final Request request;
    private final boolean forWebSocket;

    ApplicationInterceptorChain(int index, Request request, boolean forWebSocket) {
      this.index = index;
      this.request = request;
      this.forWebSocket = forWebSocket;
    }

   -----代码省略-----
    @Override public Response proceed(Request request) throws IOException {
      // If there's another interceptor in the chain, call that.
      if (index < client.interceptors().size()) {
        //这里获得下一个的ApplicationInterceptorChain 主要是index的值每次执行一个拦截器 +1
        Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
        //获得当前的拦截器
        Interceptor interceptor = client.interceptors().get(index);
        //这里开始执行下一个拦截器。自定义拦截器会实现Interceptor(示例代码下面会贴出)
        Response interceptedResponse = interceptor.intercept(chain);

        if (interceptedResponse == null) {
          throw new NullPointerException("application interceptor " + interceptor
                  + " returned null");
        }

        return interceptedResponse;
      }

      // No more interceptors. Do HTTP.(如果没有其他的拦截器,则执行HTTP请求)
      //这里是关键
      return getResponse(request, forWebSocket);
    }
  }
  • 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

拦截器示例代码,以自定义HostSelectionInterceptor 为例

public static final class HostSelectionInterceptor implements Interceptor {
         //上面提到的interceptor.intercept(chain);它实际调用的是以下方法
         @Override
        public Response intercept(Chain chain) throws IOException {
        // chain.proceed(chain.request()),该方法执行调用会执行下一个拦截器.
        //如此循环,直到所有的拦截器走完,然后执行HTTP请求
        return chain.proceed(chain.request());
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
3.3 OKHTTP的HTTP请求流程

当所有的拦截器都执行完之后,就开始执行HTTP请求了,方法为:getResponse(request, forWebSocket),其实现代码如下:

Response getResponse(Request request, boolean forWebSocket) throws IOException {
   //......代码省略......

    // Create the initial HTTP engine. Retries and redirects need new engine for each attempt.
    //HttpEngine 重试或者重定向都需要一个HTTPEngin 
    engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);

    int followUpCount = 0;  //重定向的数目
    while (true) {
      if (canceled) {
        //HttpEngine释放连接池
        engine.releaseStreamAllocation();
        throw new IOException("Canceled");
      }

      boolean releaseConnection = true;
      try {
      //发送请求,本地socket与远程服务器进行连接
        engine.sendRequest();  
        //读取服务器返回的响应数据
        engine.readResponse();
        releaseConnection = false;
      } catch (RequestException e) {

       //....代码省略....
        }

        // Give up; recovery is not possible.
        throw e;
      } finally {
        // We're throwing an unchecked exception. Release any resources.
        if (releaseConnection) {
          StreamAllocation streamAllocation = engine.close();
          streamAllocation.release();
        }
      }
      //获得响应数据
      Response response = engine.getResponse();
      //获得重定向请求的Request 数据
      Request followUp = engine.followUpRequest();

      if (followUp == null) {
        if (!forWebSocket) {
          engine.releaseStreamAllocation();
        }
        return response;
      }

      StreamAllocation streamAllocation = engine.close();

      if (++followUpCount > HttpEngine.MAX_FOLLOW_UPS) {
        streamAllocation.release();
        throw new ProtocolException("Too many follow-up requests: " + followUpCount);
      }

      if (!engine.sameConnection(followUp.url())) {
        streamAllocation.release();
        streamAllocation = null;
      } else if (streamAllocation.stream() != null) {
        throw new IllegalStateException("Closing the body of " + response
                + " didn't close its backing stream. Bad interceptor?");
      }

      request = followUp;
      //按照HttpEngine 的定义,每个重连或者重定向的连接,都需要新建一个httpEngine
      engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null,
              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

说明:上一段代码中有四个方法为核心方法,如下:

核心方法 说明
engine.sendRequest() 发送请求,本地socket与远程服务器进行连接
engine.readResponse() 读取服务器返回的响应数据
engine.getResponse() 获得服务器返回的响应数据
engine.followUpRequest() 重定向的请求数据

下面我以此讲解四个方法的实现

3.3.1 engine.sendRequest() 发送连接请求
public void sendRequest() throws RequestException, RouteException, IOException {
    if (cacheStrategy != null) return; // Already sent.
    if (httpStream != null) throw new IllegalStateException();
    //设置网络请求所需的字段cookeis、headers等字段
    Request request = networkRequest(userRequest);
    //初始化一个内部的缓存
    InternalCache responseCache = Internal.instance.internalCache(client);
    //cacheCandidate 缓存中的响应数据
    Response cacheCandidate = responseCache != null ? responseCache.get(request): null;

    long now = System.currentTimeMillis();
    //缓存策略
    cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();
    networkRequest = cacheStrategy.networkRequest;
    cacheResponse = cacheStrategy.cacheResponse;

    if (responseCache != null) {
      responseCache.trackResponse(cacheStrategy);
    }

    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) {
      userResponse = new Response.Builder()
          .request(userRequest)
          .priorResponse(stripBody(priorResponse))
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(EMPTY_BODY)
          .sentRequestAtMillis(sentRequestMillis)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build();
      return;
    }

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

-----------------------------------------分割线----------------------------------------------

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean success = false;
    try {
      //Socket连接
      httpStream = connect();
      httpStream.setHttpEngine(this);

      if (writeRequestHeadersEagerly()) {
        long contentLength = OkHeaders.contentLength(request);
        if (bufferRequestBody) {
          if (contentLength > Integer.MAX_VALUE) {
            throw new IllegalStateException("Use setFixedLengthStreamingMode() or "
                + "setChunkedStreamingMode() for requests larger than 2 GiB.");
          }

          if (contentLength != -1) {
            // Buffer a request body of a known length.
            httpStream.writeRequestHeaders(networkRequest);
            requestBodyOut = new RetryableSink((int) contentLength);
          } else {
            // Buffer a request body of an unknown length. Don't write request headers until the
            // entire body is ready; otherwise we can't set the Content-Length header correctly.
            requestBodyOut = new RetryableSink();
          }
        } else {
          httpStream.writeRequestHeaders(networkRequest);
          requestBodyOut = httpStream.createRequestBody(networkRequest, contentLength);
        }
      }
      success = true;
    } finally {
      // If we're crashing on I/O or otherwise, don't leak the cache body.
      if (!success && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }
  }
  • 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

说明:这段代码分两个部分讲解,由分割线分为上下两个部分,其中上半部分涉及缓存策略,而下半部分涉及http请求的连接。 
1、上半部分,缓存

  if (cacheStrategy != null) return; // Already sent.
    //-------代码省略------
    //cacheCandidate 缓存中的响应数据
    Response cacheCandidate = responseCache != null ? responseCache.get(request): null;
    long now = System.currentTimeMillis();
    //缓存策略
    cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();
    networkRequest = cacheStrategy.networkRequest;
    cacheResponse = cacheStrategy.cacheResponse;
    //-------代码省略------
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

首先看下 responseCache.get(request)这个方法实现,它最终调用的是Cache类中的get(Request request)方法

Response get(Request request) {
    //将请求的URl进行MD5加密处理
    String key = urlToKey(request);
    //Snapshot 快照,存储每一个请求的cache在特定时刻的内容
    DiskLruCache.Snapshot snapshot;
    Entry entry;
    try {
      snapshot = cache.get(key); //根据请求中的URl的MD5码获得snapshot(快照),里面主要是对日志文件进行操作
      if (snapshot == null) {
        return null;
      }
    } catch (IOException e) {
      // Give up because the cache cannot be read.
      return null;
    }

    try {
    //Entry 每一个请求的缓存对应一个Entry
      entry = new Entry(snapshot.getSource(ENTRY_METADATA));
    } catch (IOException e) {
      Util.closeQuietly(snapshot);
      return null;
    }
    //快照缓存中的响应数据
    Response response = entry.response(snapshot);

    if (!entry.matches(request, response)) {
      Util.closeQuietly(response.body());
      return null;
    }
    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

下面再看下CacheStrategy.Factory(now, request, cacheCandidate).get()这个方法,获取缓存策略。

    public CacheStrategy get() {
    //获取缓存策略,我们再看下getCandidate()的具体实现,代码如下
      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;
    }

    /** Returns a strategy to use assuming the request can use the network. */
    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.
      //假如请求方式是HTTPs,但是handshake为空,则丢弃缓存响应
      if (request.isHttps() && cacheResponse.handshake() == null) {
        return new CacheStrategy(request, null);
      }

      //如果缓存不能被保存,则放弃缓存响应
      if (!isCacheable(cacheResponse, request)) {
        return new CacheStrategy(request, null);
      }

      CacheControl requestCaching = request.cacheControl();
      //如果请求参数中设置了on-cache,那么放弃缓存
      if (requestCaching.noCache() || hasConditions(request)) {
        return new CacheStrategy(request, null);
      }

      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;
      CacheControl responseCaching = cacheResponse.cacheControl();
      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());
      }

      Request.Builder conditionalRequestBuilder = request.newBuilder();

      if (etag != null) {
        conditionalRequestBuilder.header("If-None-Match", etag);
      } else if (lastModified != null) {
        conditionalRequestBuilder.header("If-Modified-Since", lastModifiedString);
      } else if (servedDate != null) {
        conditionalRequestBuilder.header("If-Modified-Since", servedDateString);
      }

      Request conditionalRequest = conditionalRequestBuilder.build();
      return hasConditions(conditionalRequest)
          ? new CacheStrategy(conditionalRequest, cacheResponse) //如果缓存数据被修改,则采用该策略
          : new CacheStrategy(conditionalRequest, null); //否则摒弃缓存响应
    }
  • 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

2、下半部分,连接服务器

 // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean success = false;
    try {
      //Socket连接
      httpStream = connect();
      httpStream.setHttpEngine(this);

     //------代码省略--------
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我们看下connect()这个方法实现,它的最终实现是调用了StreamAllocation类中的newStream()方法

public HttpStream newStream(int connectTimeout, int readTimeout, int writeTimeout,
      boolean connectionRetryEnabled, boolean doExtensiveHealthChecks)
      throws RouteException, IOException {
    try {
    //连接服务器
      RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
          writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);

    //-----代码省略-------
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

findHealthyConnection(connectTimeout, readTimeout,writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks)方法的实现,他最终调用的是

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

      RealConnection allocatedConnection = this.connection;
      if (allocatedConnection != null && !allocatedConnection.noNewStreams) {
        return allocatedConnection;
      }

      // 尝试从连接池中找到与该连接地址相同的请求,并返回该连接.
      RealConnection pooledConnection = Internal.instance.get(connectionPool, address, this);
      if (pooledConnection != null) {
        this.connection = pooledConnection;
        return pooledConnection;
      }

      selectedRoute = route;
    }
    if (selectedRoute == null) {
      selectedRoute = routeSelector.next();
      synchronized (connectionPool) {
        route = selectedRoute;
        refusedStreamCount = 0;
      }
    }

    //新的路线,建立连接
    RealConnection newConnection = new RealConnection(selectedRoute);
    acquire(newConnection);
    //将新建立的连接添加到连接池中
    synchronized (connectionPool) {
      Internal.instance.put(connectionPool, newConnection);
      this.connection = newConnection;
      if (canceled) throw new IOException("Canceled");
    }
    //开始连接
    newConnection.connect(connectTimeout, readTimeout, writeTimeout, address.connectionSpecs(),
        connectionRetryEnabled);
    routeDatabase().connected(newConnection.route());
    return newConnection;
  }
  • 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

.connect(connectTimeout, readTimeout, writeTimeout, address.connectionSpecs(),connectionRetryEnabled)方法实现,最终调用的是

public void connect(int connectTimeout, int readTimeout, int writeTimeout,
                      List<ConnectionSpec> connectionSpecs, boolean connectionRetryEnabled) throws RouteException {
    //------代码省略------

    while (protocol == null) {  //假如协议protocol为null
      try {
        if (route.requiresTunnel()) {  //假如sslSocket不为空并且代理类型为HTTP,则为true
          buildTunneledConnection(connectTimeout, readTimeout, writeTimeout,
              connectionSpecSelector);  //创建连接通道,包括socket连接,SSL、TLS协议证书等连接
        } else {
          buildConnection(connectTimeout, readTimeout, writeTimeout, connectionSpecSelector);
        }
      } catch (IOException e) {
     //-----代码省略-------
      }
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

我们再看下buildTunneledConnection(connectTimeout, readTimeout, writeTimeout,connectionSpecSelector)这个方法

/**
   * Does all the work to build an HTTPS connection over a proxy tunnel. The catch here is that a
   * proxy server can issue an auth challenge and then close the connection.
   */
  private void buildTunneledConnection(int connectTimeout, int readTimeout, int writeTimeout,
      ConnectionSpecSelector connectionSpecSelector) throws IOException {
    Request tunnelRequest = createTunnelRequest();//创建一个通道请求
    HttpUrl url = tunnelRequest.url();
    int attemptedConnections = 0;
    int maxAttempts = 21; //最大的连接尝试次数
    while (true) {
      if (++attemptedConnections > maxAttempts) {
        throw new ProtocolException("Too many tunnel connections attempted: " + maxAttempts);
      }
      //连接socket
      connectSocket(connectTimeout, readTimeout, writeTimeout, connectionSpecSelector);

      tunnelRequest = createTunnel(readTimeout, writeTimeout, tunnelRequest, url);

      if (tunnelRequest == null) break; // Tunnel successfully created.

      // The proxy decided to close the connection after an auth challenge. We need to create a new
      // connection, but this time with the auth credentials.
      Util.closeQuietly(rawSocket);
      rawSocket = null;
      sink = null;
      source = null;
    }

    //建立连接,包括握手等功能
    establishProtocol(readTimeout, writeTimeout, connectionSpecSelector);
  }
  • 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

我们再看下establishProtocol(readTimeout, writeTimeout, connectionSpecSelector);这个方法的实现

private void establishProtocol(int readTimeout, int writeTimeout,
      ConnectionSpecSelector connectionSpecSelector) throws IOException {
    if (route.address().sslSocketFactory() != null) {
      //与服务器进行握手连接
      connectTls(readTimeout, writeTimeout, connectionSpecSelector);
    } else {
      protocol = Protocol.HTTP_1_1;
      socket = rawSocket;
    }
    //如果网络请求的协议是spdy/3.1 或者h2 时,则执行如下方法
    if (protocol == Protocol.SPDY_3 || protocol == Protocol.HTTP_2) {
      socket.setSoTimeout(0); // Framed connection timeouts are set per-stream.

      FramedConnection framedConnection = new FramedConnection.Builder(true)
              .socket(socket, route.address().url().host(), source, sink)
              .protocol(protocol)
              .listener(this)
              .build();
      framedConnection.start();

      // Only assign the framed connection once the preface has been sent successfully.
      this.allocationLimit = framedConnection.maxConcurrentStreams();
      this.framedConnection = framedConnection;
    } else {
      this.allocationLimit = 1;
    }
  }
  • 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

小结:至此,HttpEngine的发送请求方法的流程到这里已经走完,下面讲解engine.readResponse()方法

3.3.2 engine.readResponse() 读取响应数据

改方法的实现如下;

/**
   * Flushes the remaining request header and body, parses the HTTP response headers and starts
   * reading the HTTP response body if it exists.
   */
  public void readResponse() throws IOException {
    if (userResponse != null) {
      return; // Already ready.
    }
    if (networkRequest == null && cacheResponse == null) {
      throw new IllegalStateException("call sendRequest() first!");
    }
    if (networkRequest == null) {
      return; // No network response to read.
    }

    Response networkResponse;

    if (forWebSocket) {
      httpStream.writeRequestHeaders(networkRequest);
      networkResponse = readNetworkResponse();
    } else if (!callerWritesRequestBody) {  //callerWritesRequestBody此值为fale
      networkResponse = new NetworkInterceptorChain(0, networkRequest,
          streamAllocation.connection()).proceed(networkRequest);  //这里读取网络返回的响应数据
    } else {
      // Emit the request body's buffer so that everything is in requestBodyOut.
      if (bufferedRequestBody != null && bufferedRequestBody.buffer().size() > 0) {
        bufferedRequestBody.emit();
      }

      // Emit the request headers if we haven't yet. We might have just learned the Content-Length.
      if (sentRequestMillis == -1) {
        if (OkHeaders.contentLength(networkRequest) == -1
            && requestBodyOut instanceof RetryableSink) {
          long contentLength = ((RetryableSink) requestBodyOut).contentLength();
          networkRequest = networkRequest.newBuilder()
              .header("Content-Length", Long.toString(contentLength))
              .build();
        }
        httpStream.writeRequestHeaders(networkRequest);
      }

      // Write the request body to the socket.
      if (requestBodyOut != null) {
        if (bufferedRequestBody != null) {
          // This also closes the wrapped requestBodyOut.
          bufferedRequestBody.close();
        } else {
          requestBodyOut.close();
        }
        if (requestBodyOut instanceof RetryableSink) {
          httpStream.writeRequestBody((RetryableSink) requestBodyOut);
        }
      }

      networkResponse = readNetworkResponse();
    }

    receiveHeaders(networkResponse.headers());

    // If we have a cache response too, then we're doing a conditional get.
    //如果缓存不为空,并且缓存数据有更新,则将新数据与之前的缓存数据通过调用responseCache.update方法进行更新操作,并将数据进行压缩输出(gzip)
    if (cacheResponse != null) {
      if (validate(cacheResponse, networkResponse)) {
        userResponse = cacheResponse.newBuilder()
            .request(userRequest)
            .priorResponse(stripBody(priorResponse))
            .headers(combine(cacheResponse.headers(), networkResponse.headers()))
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build();
        networkResponse.body().close();
        releaseStreamAllocation();

        // Update the cache after combining headers but before stripping the
        // Content-Encoding header (as performed by initContentStream()).
        InternalCache responseCache = Internal.instance.internalCache(client);
        responseCache.trackConditionalCacheHit();
        responseCache.update(cacheResponse, userResponse);
        userResponse = unzip(userResponse);
        return;
      } else {
        closeQuietly(cacheResponse.body());
      }
    }
    //如果没有缓存数据,则直接返回新的数据
    userResponse = networkResponse.newBuilder()
        .request(userRequest)
        .priorResponse(stripBody(priorResponse))
        .cacheResponse(stripBody(cacheResponse))
        .networkResponse(stripBody(networkResponse))
        .build();

    if (hasBody(userResponse)) {
      maybeCache();
      userResponse = unzip(cacheWritingResponse(storeRequest, userResponse));
    }
  }

猜你喜欢

转载自blog.csdn.net/qq_32671919/article/details/80083568
ok3
OK
今日推荐