OkHttp3 源码解析执行流程

OkHttp是一款网络请求框架,【OkHttp传送门】,为了在开发中使用的更加得心应手,必然的要去探究其源码,分析其中的工作原理,而且还能学习框架的设计思想。文章主要对OkHttp整体的工作流程进行分析,所以一些操作方法并没有涉及,读者可以通过传送门阅读文档自行实践。在分析之前,先看一张整体的流程图(本文内容会根据图的流程展开):

okhttp流程.png

OkHttp请求网络的简单示例

private static final String URL_CONTENT = "https://www.baidu.com/";

    public static void doOkHttp() {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)  //连接失败后进行重连
                .build();

        final Request request = new Request.Builder()              
                .url(URL_CONTENT)
                .build();
        
        //异步方式请求网络
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //请求失败
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //请求成功,对response进行处理
                
            }
        });
    }

上面的代码,首先创建一个okHttpClient对象,调用newCall()并且request作为参数传入,然后执行enqueue(),并且new一个Callback,请求结果的回调,这个过程是异步的。

//execute()是同步的方式请求网络,会阻塞UI线程,所以一般情况都是通过异步的方式请求网络
okHttpClient.newCall(request).execute();

1、OkHttpClient的build()过程。

public Builder() {
      dispatcher = new Dispatcher();  //异步请求调度器
      protocols = DEFAULT_PROTOCOLS;//请求协议集合,默认为http/1.1和Http/2
      connectionSpecs = DEFAULT_CONNECTION_SPECS;//连接规格
      eventListenerFactory = EventListener.factory(EventListener.NONE);//事件监听器
      proxySelector = ProxySelector.getDefault();//代理选择器
      cookieJar = CookieJar.NO_COOKIES;//http cookies 提供持久化策略
      socketFactory = SocketFactory.getDefault(); //socket工厂类
      hostnameVerifier = OkHostnameVerifier.INSTANCE;//对host基本接口的验证
      certificatePinner = CertificatePinner.DEFAULT; //约束的信任证书
      proxyAuthenticator = Authenticator.NONE;//代理身份认证
      authenticator = Authenticator.NONE;
      connectionPool = new ConnectionPool();//连接复用池
      dns = Dns.SYSTEM;//默认使用系统的dns
      followSslRedirects = true; //遵循SSL重定向
      followRedirects = true;//普通重定向
      retryOnConnectionFailure = true;//连接失败后进行重新连接
      connectTimeout = 10_000;//连接超时时间
      readTimeout = 10_000;//读取数据超时时间
      writeTimeout = 10_000;//发送数据超时时间
      pingInterval = 0;//时间间隔
    }

public OkHttpClient build() {
      return new OkHttpClient(this);
    }
OkHttpClient(Builder builder) {
    this.dispatcher = builder.dispatcher;
    this.proxy = builder.proxy;
    this.protocols = builder.protocols;
    this.connectionSpecs = builder.connectionSpecs;
    this.interceptors = Util.immutableList(builder.interceptors);//自定义的拦截器
    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);//网络拦截器
    this.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;//创建OkHttpClient对象时的自定义缓存
    this.internalCache = builder.internalCache;//内部缓存
    this.socketFactory = builder.socketFactory;

    boolean isTLS = false;
    for (ConnectionSpec spec : connectionSpecs) {
      isTLS = isTLS || spec.isTls();
    }

    if (builder.sslSocketFactory != null || !isTLS) {
      this.sslSocketFactory = builder.sslSocketFactory;
      this.certificateChainCleaner = builder.certificateChainCleaner;
    } else {
      X509TrustManager trustManager = systemDefaultTrustManager();
      this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
      this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
    }

    this.hostnameVerifier = builder.hostnameVerifier;
    this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
        certificateChainCleaner);
    this.proxyAuthenticator = builder.proxyAuthenticator;
    this.authenticator = builder.authenticator;
    this.connectionPool = builder.connectionPool;
    this.dns = builder.dns;
    this.followSslRedirects = builder.followSslRedirects;
    this.followRedirects = builder.followRedirects;
    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
    this.connectTimeout = builder.connectTimeout;
    this.readTimeout = builder.readTimeout;
    this.writeTimeout = builder.writeTimeout;
    this.pingInterval = builder.pingInterval;

    if (interceptors.contains(null)) {
      throw new IllegalStateException("Null interceptor: " + interceptors);
    }
    if (networkInterceptors.contains(null)) {
      throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
    }
  }

通过建造者模式创建OkHttpClient对象,并且配置各种参数。

2、Request的Builder()的过程

public Builder() {
      this.method = "GET"; //请求方法,默认GET
      this.headers = new Headers.Builder();//创建请求头
    }

public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);
    }

Request(Builder builder) {
    this.url = builder.url; //请求url
    this.method = builder.method;//请求方法
    this.headers = builder.headers.build();//请求头
    this.body = builder.body;//请求体
    this.tag = builder.tag != null ? builder.tag : this;
  }

Request也是以建造者模式创建对象,配置参数。关于HTTP报文结构图(左图对应Request,右图对应Response):


HTTP报文结构.png

3、okHttpClient.newCall()

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

//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;
  }

调用newCall()实际返回的是一个RealCall(继承自Call)对象。RealCall内部封装了网络请求和请求结果回调。那么,上面的异步请求实际调用的是RealCall的enqueue()方法。

4、RealCall # enqueue()

public void enqueue(Callback responseCallback) {
    synchronized (this) {
      //若任务已经执行,则抛出IllegalStateException
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //跟踪调用堆栈
    captureCallStackTrace();
    //监听开始事件
    eventListener.callStart(this);
    // 1
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

上面代码的核心是注释1处,client.dispatcher()返回一个Dispatcher对象,异步请求调度器,里面会对任务进行分辨,是立刻执行还是放入等待队列。AsyncCall继承NamedRunnable(实现了Runnable接口)类,接着进入Dispatcher的enqueue()方法:

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

从代码可以发现,Dispatcher的enqueue()是一个同步方法,maxRequests是最大请求数(值为64),maxRequestsPerHost是Host最大请求数据(值为5),当满足这两个条件时,把任务添加到执行队列runningAsyncCalls,立刻执行,否则加入等待队列readyAsyncCalls,等待异步调用。executorService()内部创建了一个执行任务的线程池,并且返回一个执行对象ExecutorService。
executorService()的内部实现:

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

以单例模式中的懒汉模式创建了一个线程池。其实上面创建的线程池和我们直接用Executors的newCachedThreadPool()创建是类似的,核心线程数为0,线程空闲时的超时时间60s,直接提交策略。关于线程池的分析,可以阅读【探索Java 线程池】这篇文章。在这里,往线程池中添加的任务对象是AsyncCall,那么看看AsyncCall的内部实现:

final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

    String host() {
      return originalRequest.url().host();
    }

    Request request() {
      return originalRequest;
    }

    RealCall get() {
      return RealCall.this;
    }

    @Override 
     protected void execute() {
      boolean signalledCallback = false;
      try {
        //核心请求
        Response response = getResponseWithInterceptorChain();
        //根据是否取消RetryAndFollowUpInterceptor,分别回调onFailure或onResponse
        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 {  
        //请求完毕,移除runningAsyncCalls中当前执行的Call。
        //并且查找等待队列readyAsyncCalls是否存在任务,存在,则添加执行队列runningAsyncCalls,然后执行任务
        //如果runningAsyncCalls不存在任务,且idleCallback不为null,则启动空闲状态Runnable
        client.dispatcher().finished(this);
      }
    }
  }

NamedRunnable实现了Runnable接口,在其run()方法内部调用了execute()方法,这里运用了设计模式中的模板模式,那么,这里就把任务交给了AsyncCall的execute()方法。通过代码的注释可以知道,把请求交由了getResponseWithInterceptorChain()方法,这个方法直译过来意思就是:用拦截器链获取响应报文。而方法内部也正运用了设计模式中的责任链模式。

模板模式
优点:封装不变部分,扩展可变部分;提取公共部分代码,便于维护。
缺点:在代码阅读方面可能会带来相对的难度。

责任链模式
优点:对请求者和处理者关系解耦,提高了代码灵活性。
缺点:如果处理者太多,过多的遍历会导致性能降低。

回到OkHttp的请求流程,上面已经把任务交由了getResponseWithInterceptorChain()方法,那么,看下其内部实现。

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    //初始化OkHttpClient对象时添加的自定义interceptors
    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) {  
      //添加用户自定义的networkInterceptors
      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);
  }

getResponseWithInterceptorChain()内部添加各种拦截器,利用RealInterceptorChain将已有的拦截器进行串联,然后proceed()开始遍历拦截器。

 public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
  ... ....//省略部分代码

    // Call the next interceptor in the chain.
    //遍历拦截器链,index代表责任链中拦截器的下标,初始值为0
    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;
  }

5、分析各个拦截器的作用

  • RetryAndFollowUpInterceptor:在连接失败后进行重新连接,必要时进行重定向,如果调用被取消,可能会抛出IOException
  • BridgeInterceptor:构建访问网络的桥梁,首先,将用户请求转换成网络请求,然后访问网络,最后将网络响应转换成用户响应。
  • CacheInterceptor:缓存拦截器,从缓存中获取服务器请求,或者把服务器响应写入缓存中。
  • ConnectInterceptor:打开一个连接,去连接目标服务器。
  • CallServerInterceptor:拦截器链中的最后一个链点,通过网络请求服务器。

链式执行流程:

链式流程.png

5.1、RetryAndFollowUpInterceptor # intercept()

public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Call call = realChain.call();
    EventListener eventListener = realChain.eventListener();
    
    //用于分配一个到服务器特定的HttpStream,内部封装了ConnectionPool连接池,管理Http的连接
    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) {
        // The attempt to connect via a route failed. The request will not have been sent.
        if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
          throw e.getLastConnectException();
        }
        releaseConnection = false;
        continue;
      } catch (IOException e) {
        // An attempt to communicate with a server failed. The request may have been sent.
        boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
        if (!recover(e, streamAllocation, requestSendStarted, request)) throw e;
        releaseConnection = false;
        continue;
      } 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.
      //检测前一个Response
      if (priorResponse != null) {
        response = response.newBuilder()
            .priorResponse(priorResponse.newBuilder()
                    .body(null)
                    .build())
            .build();
      }
      
      Request followUp = followUpRequest(response, streamAllocation.route());
      //followUp为null,表示不要重定向,释放资源并且返回response
      if (followUp == null) {
        if (!forWebSocket) {
          streamAllocation.release();
        }
        return response;
      }
      //关闭response的body
      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());
      }

      //检测地址是否相同,释放旧连接,重新创建一个新的连接
      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;
    }
  }

5.2、BridgeInterceptor # intercept()

public Response intercept(Chain chain) throws IOException {
    Request userRequest = chain.request();
    Request.Builder requestBuilder = userRequest.newBuilder();
    //将用户的Request构造成服务器的Request
    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");
    }
 
    //使用Gzip压缩
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");
    }
  
    //设置cookies
    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());
    }
    
    //传入已构造好的服务器Request,调用下一个拦截器,获取服务器的networkResponse 
    Response networkResponse = chain.proceed(requestBuilder.build());
    
    //保存networkResponse的cookie
    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
   
    //后续则是把networkResponse构造成用户的response
    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();
  }

5.3、CacheInterceptor # intercept()

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;

    //从缓存中追踪Response
    if (cache != null) {
      cache.trackResponse(strategy);
    }

    //如果缓存不适用,则关闭
    if (cacheCandidate != null && cacheResponse == null) {
      closeQuietly(cacheCandidate.body()); 
    }

    // 如果网络被禁止,且缓存为空,则返回失败
    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 (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }

    Response networkResponse = null;
    try {
      //调用下一个拦截者,从网络获取Response 
      networkResponse = chain.proceed(networkRequest);
    } finally {
      // 关闭body,防止内存泄露
      if (networkResponse == null && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }

    // 如果缓存中存在Response,同时检测networkResponse是否被修改
    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 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;
  }

5.4、ConnectInterceptor # intercept()

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的实现类有Http1Codec和Http2Codec
    //分别对应Http1.1和Http2
    //HttpCodec主要是对Http请求和Http响应进行编解码
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    RealConnection connection = streamAllocation.connection();
    
    //调用下一个拦截器
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }

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);
      //根据具体的resultConnection 创建resultCodec对象
      HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);

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

5.5、CallServerInterceptor # intercept()

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;
    
    //检测是否有body的请求方法
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {

      //如果请求头是"100-continue",等待服务器的响应
      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();
       
        //将请求体转换成sink,并封装在CountingSink 内部
        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();

    //从httpCodec中获取响应头
    if (responseBuilder == null) {
      realChain.eventListener().responseHeadersStart(realChain.call());
      responseBuilder = httpCodec.readResponseHeaders(false);
    }

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

    //如果服务器返回的状态码是100,再次尝试读取具体的response
    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);

    //如果是WebSocket,并且返回状态码为101,表示响应body为空
    if (forWebSocket && code == 101) {
      response = response.newBuilder()
          .body(Util.EMPTY_RESPONSE)
          .build();
    } else {
      //读取body
      response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();
    }
     
    //如果响应头部是"close",关闭流
    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;
  }

到这里,OkHttp的执行流程就分析完毕了。

关于OkHttp3系列的其它文章:
OkHttp3 源码解析 连接池的复用
OkHttp3源码解析内部缓存

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容