OkHttp源码分析

写在前面

OkHttp版本3.11.0

前置知识

责任链模式

简单使用
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(new Test1Interceptor())
                .addNetworkInterceptor(new Test2Interceptor())
                .build();
        Request request = new Request.Builder()
                    .url("https://github.com")
                    .build();
        //execute, 同步执行
        Response response = client.newCall(request).execute();
        
        //enqueue 异步执行
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {                
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });

public class Test1Interceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        //此处可以对request(请求信息)添加自己的逻辑
        //比如添加header
        //修改host url
        Response response = chain.proceed(request);
        //此处可以对response(返回结果)添加自己的逻辑
        //模拟接口返回结果
        return response;
    }
}
public class Test2Interceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        //此处可以对request(请求信息)添加自己的逻辑
        //比如添加header
        //修改host url
        Response response = chain.proceed(request);
        //此处可以对response(返回结果)添加自己的逻辑
        //模拟接口返回结果
        return response;
    }
}

从后往前看, 最后一个方法是okhttp3.Call#enqueue, 接口里的方法, 所以, 我们看okhttp3.OkHttpClient#newCall

OkHttpClient#newCall

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

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

看到这里, 我们发现, 这里实际上就是创建了RealCall, 它是Call的实现类, 最后执行它的okhttp3.RealCall#enqueue方法, 实现异步接口调用. 所以我们看下okhttp3.RealCall#enqueue

okhttp3.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));
  }

首先, okhttp3.OkHttpClient#dispatcher方法返回的是okhttp3.Dispatcher, 然后执行okhttp3.Dispatcher#enqueue
所以, 我们分析的重点, 变成了okhttp3.Dispatcher#enqueue

okhttp3.Dispatcher#enqueue

  synchronized void enqueue(AsyncCall call) {
     //立即执行的条件
    //1. 正在执行请求的数量小于maxRequests(默认值64)
    //2.正在执行的请求中, 跟本次请求call的host url一样 的call的数量小于maxRequestsPerHost(默认值5)
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      //加到正在执行的队列中(第1个条件要用到runningAsyncCalls)
      runningAsyncCalls.add(call);
      //交给线程池执行call
      executorService().execute(call);
    } else {
      //加入到等待队列中等待执行
      readyAsyncCalls.add(call);
    }
  }

到这里我们知道了, enqueue方法, 最后实际上是把AsyncCall 交给线程池执行. 所以, 我们接下来看AsyncCall
AsyncCall是NamedRunnable的子类, 而NamedRunnable实现了Runnable, 并把Runnable#run中执行了抽象方法NamedRunnable#execute. 实际的执行就是okhttp3.RealCall.AsyncCall#execute

okhttp3.RealCall.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 {
        //通知dispatcher, call已经执行完
        //dispatcher把call从正在执行的请求队列中移除call
        client.dispatcher().finished(this);
      }
    }

这里的关键就是Response response = getResponseWithInterceptorChain();
getResponseWithInterceptorChain方法直接就返回了结果response. 所以, 真正的请求应该发生在getResponseWithInterceptorChain方法中.

RealCall#getResponseWithInterceptorChain

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List 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));
    //注意第5个参数index传了0
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }

这个方法做的就是构建Interceptor.Chain对象, 并执行chain.proceed方法.
这个方法也是我们理解OkHttp的拦截器Interceptor机制的第一个关键点
需要注意的是, 列表interceptors中我们依次传入了我们设置的 interceptors/retryAndFollowUpInterceptor/BridgeInterceptor/CacheInterceptor/ConnectInterceptor/networkInterceptors/CallServerInterceptor.这里他们具体做了什么, 我们先放一边, 继续看chain.proceed. 这里的chain实际上是RealInterceptorChain.

RealInterceptorChain#proceed

  @Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }
  //实际执行了这个方法
  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
     //...检查参数
    //构建RealInterceptorChain 
    //注意第5个参数, 这里我们的index是0(getResponseWithInterceptorChain方法传入了0), 
    //所以, 新构建的RealInterceptorChain 中的index变成了1
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    //取出第0个interceptor, 
    //这个时候我们回头重新看下RealCall#getResponseWithInterceptorChain
    //如果我们设置了interceptor , 那就会是我们通过OkHttpClient.Builder#addInterceptor设置的interceptor, 
    //如果我们没设置interceptor, 此处就是retryAndFollowUpInterceptor
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    //...结果检查
    return response;
  }

像示例中, 我们通过OkHttpClient.Builder#addInterceptor设置的Test1Interceptor, 此时, 就会执行我们创建的Test1Interceptor#intercept方法.在该方法中, 我们执行chain.proceed来获取结果, 也即是RealInterceptorChain#proceed

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
     //此时index已经变成了1
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    //取出第1个interceptor,  也就是retryAndFollowUpInterceptor
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    //...结果检查
    return response;
  }

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, 前面都是null
    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 {
        //执行Chain#proceed
        //第一次执行这里, 让Chain继续往下执行
        response = realChain.proceed(request, streamAllocation, null, null);
        //拿到response 后, 做其他逻辑
        releaseConnection = false;
        //...异常处理
      }

      // 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;
      try {
        //followUpRequest方法, 对各个请求响应码code做处理
        //需要重试的返回新的request
        //不需要重试的返回null
        followUp = followUpRequest(response, streamAllocation.route());
      } catch (IOException e) {
        streamAllocation.release();
        throw e;
      }
      //如果不需要重试, 就返回结果
      if (followUp == null) {
        if (!forWebSocket) {
          streamAllocation.release();
        }
        return response;
      }

      //开始重试处理(请求失败重新请求)的逻辑
      closeQuietly(response.body());
      if (++followUpCount > MAX_FOLLOW_UPS) {
        //如果重试了20次, 结束重试
        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
        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
      request = followUp;
      priorResponse = response;
      //继续while循环
      //因为有新的request和streamAllocation 
      //重新执行while, 走response = realChain.proceed(request, streamAllocation, null, null)等逻辑
      //实现重新请求
    }
  }

简述逻辑如下:
1.执行realChain.proceed, 从chain拿到请求结果response
2.对response 响应码做判断, 如果不需要重试(比如请求成功), 就返回response
3.如果需要重定向, 就构建新的request和streamAllocation, 然后重新执行步骤1, 直到重试了20次或者抛出了异常

暂时, 我们先不考虑失败的情况. 这里我们继续看RealInterceptorChain#proceed
此时index已经变成了2(因为构建RealInterceptorChain的时候, 其参数index是上一个RealInterceptorChain的index+1)

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
     //此时index已经变成了2
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    //取出第2个interceptor,  也就是BridgeInterceptor
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    //...结果检查
    return response;
  }

BridgeInterceptor#intercept

  @Override public Response intercept(Chain chain) throws IOException {
    Request userRequest = chain.request();
    //...添加request的请求头
    //比如使用gzip/Content-Type/Connection等等
    Response networkResponse = chain.proceed(requestBuilder.build());
    //对结果添加额外处理
    //...比如使用GZIP对数据进行解压(如果请求头设置了gzip的话)
    return responseBuilder.build();
  }

简述逻辑如下:
1.对request添加请求头信息, 比如gzip/Cookie/Host/Content-Length
2.执行chain.proceed, 从chain获取结果response
3.处理response(比如使用GZIP解压缩)生成新的response并返回

这里chain.proceed也是执行的RealInterceptorChain#proceed, 逻辑和之前的类似, 也是获取interceptor, 执行interceptor#intercept. 这次interceptor是CacheInterceptor
我们可以小结一下RealInterceptorChain和Interceptor
1.RealCall#getResponseWithInterceptorChain中我们构建了interceptors列表
2.index从0开始, 每次index+1, 创建RealInterceptorChain, 并从interceptors取出index对应位置的interceptor, 执行interceptor#intercept
3.在Interceptor#intercept中执行RealInterceptorChain#proceed, 创建index+1的RealInterceptorChain. 在RealInterceptorChain#proceed前, 我们可以对request添加额外的处理, 在RealInterceptorChain#proceed后, 我们可以对response添加额外的处理.
4.关键是index, 这样依次实现了interceptors的遍历

看起来很麻烦, 其实就是遍历interceptors

下面我们继续看CacheInterceptor

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.
    }
    
    //1.cache没命中, 但又设置了只使用缓存
    // If we're forbidden from using the network and the cache is insufficient, fail.
    if (networkRequest == null && cacheResponse == null) {
    //只有一种情况会出现networkRequest 和cacheResponse 都为空的情况
    //请求头设置了only-if-cached, 表示只使用cache缓存, 但是cache并没有命中
      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();
    }
    //2. cache命中, cache数据有效
    // If we don't need the network, we're done.
    if (networkRequest == null) {
        //表示cache命中, 直接使用cache, 不再使用网络请求
        //比如响应头中有immutable, 表示数据不会改变
        //又比如, 当前时间并没超过响应头里的有效时间
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }
    //3. 继续执行网络请求
    Response networkResponse = null;
    try {
      networkResponse = chain.proceed(networkRequest);
    } finally {
      // If we're crashing on I/O or otherwise, don't leak the cache body.
      if (networkResponse == null && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }
    //4.如果响应码是304, 表示数据没变, 可以使用上次缓存的数据
    // 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 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();
    //5.如果自定义了InternalCache或者Cache, 就就交给InternalCache或者Cache做缓存处理
    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;
  }

对于cache的各个判断在CacheStrategy.Factory#getCandidate中, 详细逻辑可以看这个方法.
对于CacheInterceptor#intercept, 简述如下:
1.如果cache没命中, 并且只能使用缓存的情况, 设置响应码为504, 构建Response返回
2.如果cache有效命中, 用cache构建Response返回
3.使用chain.proceed取数据
4.如果响应码是304, 表示数据没变cache可用, 使用cache构建新的Response返回
5.如果设置了自定义cache, 则交给自定义cacha完成缓存

下一个执行的Interceptor是ConnectInterceptor. 我们继续看ConnectInterceptor#intercept

ConnectInterceptor#intercept

  @Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    //streamAllocation 在RetryAndFollowUpInterceptor#intercept中创建
    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 , 也获取了connection
     //这样, 下一步streamAllocation.connection()才会返回正确的RealConnection 
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    RealConnection connection = streamAllocation.connection();

    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }

如果不深究connection 以及connection pool. 这里就只是构建httpCodec 和connection .
connection 会从连接池(connection pool)获取, 如果连接池没有, 就新建RealConnection, 并把新建的RealConnection 放进连接池.

这里我们简单看下如何获取connection.
StreamAllocation#newStream -> StreamAllocation#findHealthyConnection -> StreamAllocation#findConnection
我们重点看下StreamAllocation#findConnection方法

StreamAllocation#findConnection

  private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
      int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
    //...
    synchronized (connectionPool) {
      //...异常处理

      // Attempt to use an already-allocated connection. We need to be careful here because our
      // already-allocated connection may have been restricted from creating new streams.
      releasedConnection = this.connection;
      toClose = releaseIfNoNewStreams();
      if (this.connection != null) {
        // We had an already-allocated connection and it's good.
        //如果StreamAllocation已经有了connection(比如失败重试的时候)
        result = this.connection;
        releasedConnection = null;
      }
      if (!reportedAcquired) {
        // If the connection was never reported acquired, don't report it as released!
        releasedConnection = null;
      }
      //如果StreamAllocation中connection还没初始化(还是空)
      if (result == null) {
        // Attempt to get a connection from the pool.
       //从connectionPool中获取connection 
        //注意, Internal.instance的实例是在OkHttpClient的static代码块中完成创建的
        //其get方法是pool.get(address, streamAllocation, route), 也就是从connectionPool获取connection 
        //这里是用address去连接池中匹配
        Internal.instance.get(connectionPool, address, this, null);
        if (connection != null) {
          foundPooledConnection = true;
          result = connection;
        } else {
          selectedRoute = route;
        }
      }
    }
    closeQuietly(toClose);

    if (releasedConnection != null) {
      eventListener.connectionReleased(call, releasedConnection);
    }
    if (foundPooledConnection) {
      eventListener.connectionAcquired(call, result);
    }
    //如果已经获取到connection 就返回
    if (result != null) {
      // If we found an already-allocated or pooled connection, we're done.
      return result;
    }

    // If we need a route selection, make one. This is a blocking operation.
    boolean newRouteSelection = false;
    if (selectedRoute == null && (routeSelection == null || !routeSelection.hasNext())) {
      newRouteSelection = true;
      routeSelection = routeSelector.next();
    }

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

      if (newRouteSelection) {
        // Now that we have a set of IP addresses, make another attempt at getting a connection from
        // the pool. This could match due to connection coalescing.
        //前面用host url没匹配到
        //这里我们用ip地址去连接池匹配(一个host可以对应多个ip)
        List routes = routeSelection.getAll();
        for (int i = 0, size = routes.size(); i < size; i++) {
          Route route = routes.get(i);
          Internal.instance.get(connectionPool, address, this, route);
          if (connection != null) {
            foundPooledConnection = true;
            result = connection;
            this.route = route;
            break;
          }
        }
      }
      //如果用ip还是匹配不到, 就直接创建RealConnection
      if (!foundPooledConnection) {
        if (selectedRoute == null) {
          selectedRoute = routeSelection.next();
        }

        // Create a connection and assign it to this allocation immediately. This makes it possible
        // for an asynchronous cancel() to interrupt the handshake we're about to do.
        route = selectedRoute;
        refusedStreamCount = 0;
        //直接创建RealConnection
        result = new RealConnection(connectionPool, selectedRoute);
        //给StreamAllocation#connection赋值
        acquire(result, false);
      }
    }
    //如果是从连接池中获取到的connection 就返回
    // If we found a pooled connection on the 2nd time around, we're done.
    if (foundPooledConnection) {
      eventListener.connectionAcquired(call, result);
      return result;
    }
    //如果是新建的, 就执行RealConnection#connect, 初始化连接 最终会执行socket.connect
    // Do TCP + TLS handshakes. This is a blocking operation.
    result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
        connectionRetryEnabled, call, eventListener);
    routeDatabase().connected(result.route());

    Socket socket = null;
    synchronized (connectionPool) {
      reportedAcquired = true;
        //把完成初始化的connection 放进连接池
      // Pool the connection.
      Internal.instance.put(connectionPool, result);

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

    eventListener.connectionAcquired(call, result);
    return result;
  }

简述如下:
1.使用address去连接池中查找获取connection, 如果找到就返回
2.使用address被DNS解析到的ip去连接池中查找, 如果找到就返回
3.如果还没找到就创建
4.对新建的connection初始化(执行RealConnection#connect完成初始化), Socket也是在此时创建的
5.把完成初始化的connection放进连接池

在继续往下看之前, 我们有必要再看一看RealConnection#connect -> RealConnection#connectSocket

RealConnection#connectSocket

  private void connectSocket(int connectTimeout, int readTimeout, Call call,
      EventListener eventListener) throws IOException {
    Proxy proxy = route.proxy();
    Address address = route.address();
    //新建socket对象
    rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP
        ? address.socketFactory().createSocket()
        : new Socket(proxy);

    eventListener.connectStart(call, route.socketAddress(), proxy);
    rawSocket.setSoTimeout(readTimeout);
    try {
      //socket连接
      Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout);
    } catch (ConnectException e) {
      ConnectException ce = new ConnectException("Failed to connect to " + route.socketAddress());
      ce.initCause(e);
      throw ce;
    }

    // The following try/catch block is a pseudo hacky way to get around a crash on Android 7.0
    // More details:
    // https://github.com/square/okhttp/issues/3245
    // https://android-review.googlesource.com/#/c/271775/
    try {
      //通过Okio获取socket的输入流
      source = Okio.buffer(Okio.source(rawSocket));
      //通过Okio获取socket的输出流
      sink = Okio.buffer(Okio.sink(rawSocket));
    } catch (NullPointerException npe) {
      if (NPE_THROW_WITH_NULL.equals(npe.getMessage())) {
        throw new IOException(npe);
      }
    }
  }

需要注意的是, 通过Okio, 我们获取到了socket的输入流source和输出流sink

下面, 我们看下一个Interceptor.
这里执行到了通过addNetworkInterceptor添加的Interceptor, demo里是Test2Interceptor.
到这里我们也可以回答一个问题: addInterceptor和addNetworkInterceptor有什么不同?
不同之处就是, 位置不通, addInterceptor方法添加的Interceptor的Interceptor#intercept方法先执行, addNetworkInterceptor后执行

demo中, Test2Interceptor只是简单实现. 没有别的操作, 所以我们继续往下看
下一个Interceptor也是最后一个, 是CallServerInterceptor

CallServerInterceptor#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实际上是Http1Codec
    //Http1Codec#writeRequestHeaders只干了一件事情, 就是通过sink写入数据, 但此时socket并没有发送数据, 因为没用sink.flush
    httpCodec.writeRequestHeaders(request);
    realChain.eventListener().requestHeadersEnd(realChain.call(), request);

    Response.Builder responseBuilder = null;
    //如果请求类型不是GET和HEAD, 并且body不为空(比如上传文件)
    //针对需要上传body的情况
    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.
      //针对100-continue的特殊处理
      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
        //如果请求头里Expect被设置成了100-continue
        //那就直接请求(不带body)
        httpCodec.flushRequest();
        realChain.eventListener().responseHeadersStart(realChain.call());
        //类似写入, 这里就是通过source读出socket返回的数据
        //读出返回的数据
        //如果返回100, responseBuilder 就是空
        responseBuilder = httpCodec.readResponseHeaders(true);
      }

      if (responseBuilder == null) {
        // Write the request body if the "Expect: 100-continue" expectation was met.
        //这里有两种情况
        //①使用了100-continue, 并且服务器响应了100
        //②没使用100-continue
        //这里做的就是把body(比如文件)写进sink
        realChain.eventListener().requestBodyStart(realChain.call());
        long contentLength = request.body().contentLength();
        CountingSink requestBodyOut =
            new CountingSink(httpCodec.createRequestBody(request, contentLength));
        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
       //写进sink
        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();
      }
    }
    //socket发送数据
    httpCodec.finishRequest();

    if (responseBuilder == null) {
      realChain.eventListener().responseHeadersStart(realChain.call());
      //从source读数据
      responseBuilder = httpCodec.readResponseHeaders(false);
    }
    //构建Response 
    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();
    //对response的特殊code(100/101/204/205)做额外的处理
    //...
    return response;
  }

简述流程如下:
1.buffer(sink)里写入请求信息
2.如果不是GET和HEAD并且有body(比如上传文件)
① Expect设置了100-continue, 直接发送请求, 如果服务器返回100(表示服务器可以接收请求体)
②没设置100-continue
就在buffer(sink)里写入body数据
3.socket发送buffer(sink)里的数据
4.读取socket返回的数据(source), 构建成response

这里需要注意的是, CallServerInterceptor#intercept没有像其它Interceptor执行Chain.proceed, 也即是Chain到CallServerInterceptor就走到了最后, CallServerInterceptor通过socket执行了真正的网络请求, 并把结果封装成了response返回.

总结

1. 拦截器原理: 责任链模式

自定义拦截器+OkHttp默认实现的RetryAndFollowUpInterceptor/BridgeInterceptor/CacheInterceptor/ConnectInterceptor/CallServerInterceptor共同构成链.

2. 各个拦截器作用:

RetryAndFollowUpInterceptor:失败重试
BridgeInterceptor:①添加公共请求头信息②使用GZIP解压数据(如果使用了GZIP的话)
CacheInterceptor:①如果缓存有效, 直接返回缓存数据, 不再请求 ②缓存返回的结果
ConnectInterceptor:①从连接池获取RealConnection②如果连接池里没获取到, 就创建新的RealConnection, 并且初始化socket
CallServerInterceptor:①通过socket发送请求数据②读取返回数据封装成response

你可能感兴趣的:(OkHttp源码分析)