OkHttp - Interceptors(三)

本文中源码基于OkHttp 3.6.0

  • 《OkHttp Request 请求执行流程》
  • 《OkHttp - Interceptors(一)》
  • 《OkHttp - Interceptors(二)》
  • 《OkHttp - Interceptors(三)》
  • 《OkHttp - Interceptors(四)》

这篇文章主要分析 ConnectInterceptor ,它是 OkHttp 请求链上的倒数第二个节点,其主要任务就是创建与服务器的连接。

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

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

这里的代码比较少,创建了一个 HTTP 编解码器HttpCodec和一个连接对象RealConnection,并将它们加入到请求链中,其中HttpCodec主要用于在CallServerInterceptor中向服务器发起 Request 和解析 Response。构建这两个对象的主要逻辑全部封装在StreamAllocation中,它在请求链的第一个节点RetryAndFollowupInterceptor中创建的。

来看其 newStream() 方法。

private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
    int writeTimeout, boolean connectionRetryEnabled, boolean doExtensiveHealthChecks)
    throws IOException {
  while (true) {
    RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
        connectionRetryEnabled);

    // 如果 connection 是一个新创建的,那么不用进行健康性测试
    synchronized (connectionPool) {
      if (candidate.successCount == 0) {
        return candidate;
      }
    }

    // 健康检查主要是判断 socket 是否关闭,输入输出流是否关闭等。
    // 如果连接不健康,则断开连接,并从 connectionPool 中移除。
    if (!candidate.isHealthy(doExtensiveHealthChecks)) {
      noNewStreams();
      continue;
    }

    return candidate;
  }
}

通过 findHealthyConnection() 找到一条可用的连接。

private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
    int writeTimeout, boolean connectionRetryEnabled, boolean doExtensiveHealthChecks)
    throws IOException {
  while (true) {
    RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
        connectionRetryEnabled);

    // 如果 connection 是一个新创建的,那么不用进行健康性测试
    synchronized (connectionPool) {
      if (candidate.successCount == 0) {
        return candidate;
      }
    }

    // 健康检查主要是判断 socket 是否关闭,输入输出流是否关闭等。
    // 如果连接不健康,则断开连接,并从 connectionPool 中移除。
    if (!candidate.isHealthy(doExtensiveHealthChecks)) {
      noNewStreams();
      continue;
    }

    return candidate;
  }
}

继续进入 findConnection()。

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

    // StreamAllocation 会保持了一个当前的连接,如果这个连接允许继续使用,则直接复用这个连接
    RealConnection allocatedConnection = this.connection;
    if (allocatedConnection != null && !allocatedConnection.noNewStreams) {
      return allocatedConnection;
    }

    // 从连接池中找到一个可以复用的连接
    Internal.instance.get(connectionPool, address, this);
    if (connection != null) {
      return connection;
    }

    selectedRoute = route;
  }

  // 如果没有合适的连接,那么就创建一个新的
  // 寻找一个合适的路由,如果没有找到就抛出异常,由 RetryAndFollowUpInterceptor 负责捕获并重试
  if (selectedRoute == null) {
    selectedRoute = routeSelector.next();
  }

  RealConnection result;
  synchronized (connectionPool) {
    route = selectedRoute;
    refusedStreamCount = 0;
    result = new RealConnection(connectionPool, selectedRoute);
    acquire(result);
    if (canceled) throw new IOException("Canceled");
  }

  // 执行三次握手,创建与服务器的连接
  result.connect(connectTimeout, readTimeout, writeTimeout, connectionRetryEnabled);
  routeDatabase().connected(result.route());

  Socket socket = null;
  synchronized (connectionPool) {
    // 把这个连接放进连接池,供以后复用
    Internal.instance.put(connectionPool, result);

    if (result.isMultiplexed()) {
      socket = Internal.instance.deduplicate(connectionPool, address, this);
      result = connection;
    }
  }
  closeQuietly(socket);

  return result;
}

在执行 connect() 的时候,使用 Socket 建立连接,如果请求是 HTTPS,则使用 SSLSocket 进行包装。

那么,至此客户端与服务器之间的连接就已经建立成功了,如果 OkHttpClient 中设置了 networkInterceptor 的话,下面就该把任务交给它们处理了,这里就可以看出 networkInterceptor 和 Interceptor 之间的区别,networkInterceptor 处理请求时已经建立好连接。如果没有设置 networkInterceptor,下面就该 CallServerInterceptor 出场了。

你可能感兴趣的:(OkHttp - Interceptors(三))