OkHttp学习(六) 3.10.0版本源码中的拦截器

系列文章

OkHttp学习(一) OSI七层模型和TCP四层模型
OkHttp学习(二) 3.10.0版本的简单使用及其流程梳理
OkHttp学习(三) 3.10.0版本源码阅读之线程池
OkHttp学习(四) 3.10.0版本源码阅读之构建者设计模式
OkHttp学习(五) 3.10.0版本源码阅读之责任链设计模式
OkHttp学习(六) 3.10.0版本源码中的拦截器
OkHttp学习(七) 手写OkHttp之框架搭建
OkHttp学习(八) 手写OkHttp之网络请求实现
OkHttp学习(九) OkHttp的连接池手写实现

整体架构

OkHttp学习(六) 3.10.0版本源码中的拦截器_第1张图片

上篇文章我们已经分析了各个拦截器是如何串成一条链的,下面就分析链的每个节点都做了什么事情。

RetryAndFollowUpInterceptor

重试与重定向拦截器

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

	// 创建资源分配器
    StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
        createAddress(request.url()), call, eventListener, callStackTrace);
    this.streamAllocation = streamAllocation;

    int followUpCount = 0;
    Response priorResponse = null;
	// 循环重试,如果成功直接跳出循环,如果失败,要么重试要么抛出异常,重试最大次数为20
    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.
      // 之前执行得到的priorResponse ,如果不为空,则会根据之前的priorResponse 重新创建response
      if (priorResponse != null) {
        response = response.newBuilder()
            .priorResponse(priorResponse.newBuilder()
                    .body(null)
                    .build())
            .build();
      }

	  // 根据response判断是否需要重定向,重定向的reques不为空t会放到下次重试中
      Request followUp = followUpRequest(response, streamAllocation.route());

	  // 重定向request为空,直接返回response
      if (followUp == null) {
        if (!forWebSocket) {
          streamAllocation.release();
        }
        return response;
      }

      closeQuietly(response.body());

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

      if (followUp.body() instanceof UnrepeatableRequestBody) {
        streamAllocation.release();
        throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
      }

      if (!sameConnection(response, followUp.url())) {
        streamAllocation.release();
        streamAllocation = new StreamAllocation(client.connectionPool(),
            createAddress(followUp.url()), call, eventListener, callStackTrace);
        this.streamAllocation = streamAllocation;
      } else if (streamAllocation.codec() != null) {
        throw new IllegalStateException("Closing the body of " + response
            + " didn't close its backing stream. Bad interceptor?");
      }

      request = followUp;
      priorResponse = response;
    }
  }

1.创建了StreamAllocation对象,该对象用于分配资源,后面会用到
2.调用下一个拦截器,得到response
3.根据异常结果或者响应结果判断是否要进行重试。
4.重定向的次数根据++followUpCount > MAX_FOLLOW_UPS判断不超过20次
4.对response进行处理,返回给上一个拦截器。

  • 核心功能就是 连接失败重试(Retry)

    • 在发生 RouteException 或者 IOException后,会捕获建联或者读取的一些异常,根据一定的策略判断是否是可恢复的,如果可恢复会重新创建 StreamAllocation开始新的一轮请求
  • 继续发起请求(Follow up)

    • 主要有这几种类型
      • 3xx 重定向
      • 401,407 未授权,调用 Authenticator进行授权后继续发起新的请求
      • 408 客户端请求超时,如果 Request 的请求体没有被UnrepeatableRequestBody 标记,会继续发起新的请求

BridgeInterceptor

public Response intercept(Chain chain) throws IOException {
    Request userRequest = chain.request();
    Request.Builder requestBuilder = userRequest.newBuilder();

    RequestBody body = userRequest.body();
    // 设置Content-Type
    if (body != null) {
      MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

	 // Content-Length和Transfer-Encoding互斥
      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");
      }
    }

	// 设置Host
    if (userRequest.header("Host") == null) {
      requestBuilder.header("Host", hostHeader(userRequest.url(), false));
    }

	// 设置Connection头
    if (userRequest.header("Connection") == null) {
      requestBuilder.header("Connection", "Keep-Alive");
    }

    // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
    // the transfer stream.
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");
    }

	// 创建Okhpptclitent时候配置的cookieJar,
    List cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
      // 解析成http协议的cookie格式
      requestBuilder.header("Cookie", cookieHeader(cookies));
    }

    if (userRequest.header("User-Agent") == null) {
      requestBuilder.header("User-Agent", Version.userAgent());
    }

    // 从下个链节点中取的response
    Response networkResponse = chain.proceed(requestBuilder.build());

	// 响应header, 如果没有自定义配置cookieJar==null,则什么都不做
    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

	// copy一份从下个节点取的的response
    Response.Builder responseBuilder = networkResponse.newBuilder()
        .request(userRequest);

	// 判断服务器是否支持gzip压缩格式,如果支持则交给okio压缩
    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");
      // 处理完成后,重新生成一个response
      responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
    }

	// 将响应的response返回给上个拦截器
    return responseBuilder.build();
  }

BridgeInterceptor负责在request阶段对请求头添加一些字段,在response阶段对响应进行一些gzip解压操作。
1.负责将用户构建的Request请求转化为能够进行网络访问的请求
2.将这个符合网络请求的Request进行网络请求
3.将网络请求回来的Response转化为用户可用的Response,包括gzip压缩和gzip解压

CacheInterceptor

缓存拦截器

public Response intercept(Chain chain) throws IOException {
	//1. 读取候选缓存;
    Response cacheCandidate = cache != null
        ? cache.get(chain.request())
        : null;
	// 计时开始时间
    long now = System.currentTimeMillis();

	 //2. 创建缓存策略(强制缓存,对比缓存等策略);
    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
    Request networkRequest = strategy.networkRequest;
    Response cacheResponse = strategy.cacheResponse;

    if (cache != null) {
      cache.trackResponse(strategy);
    }

    if (cacheCandidate != null && cacheResponse == null) {
      closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
    }

	//根据策略,不使用网络,缓存又没有直接报错;
    // If we're forbidden from using the network and the cache is insufficient, fail.
    if (networkRequest == null && cacheResponse == null) {
      return new Response.Builder()
          .request(chain.request())
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(Util.EMPTY_RESPONSE)
          .sentRequestAtMillis(-1L)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build();
    }

	 // 4. 根据策略,不使用网络,有缓存就直接返回;
    // If we don't need the network, we're done.
    if (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }

    Response networkResponse = null;
    try {
      // 执行下个拦截器,获得网络response
      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());
      }
    }

	// 判断是否有缓存,如果有缓存,而且下个拦截器返回的response的code为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 = 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();

	// 缓存response
    if (cache != null) {
      if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
        // Offer this request to the cache.
        CacheRequest cacheRequest = cache.put(response);
        return cacheWritingResponse(cacheRequest, response);
      }

	  // 删除无效缓存
      if (HttpMethod.invalidatesCache(networkRequest.method())) {
        try {
          cache.remove(networkRequest);
        } catch (IOException ignored) {
          // The cache cannot be written.
        }
      }
    }

	// 返回到上个拦截器
    return response;
  }
  1. 读取候选缓存;
  2. 创建缓存策略(根据头信息,判断强制缓存,对比缓存等策略);
  3. 根据策略,不使用网络,缓存又没有直接报错;
  4. 根据策略,不使用网络,有缓存就直接返回;
  5. 前面个都没有返回,读取网络结果(跑下一个拦截器);
  6. 接收到的网络结果,如果是code 304, 使用缓存,返回缓存结果(对比缓存)
  7. 读取网络结果;
  8. 对数据进行缓存;删除无效缓存;
  9. 返回网络读取的结果。

ConnectInterceptor

ConnectInterceptor负责网络连接,其本质是复用连接池中socket连接。

public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    //从拦截器链里得到StreamAllocation对象
    StreamAllocation streamAllocation = realChain.streamAllocation();

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    //创建连接等一系列的操作
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    //这里是获取前一步的connection.
    RealConnection connection = streamAllocation.connection();
	//把前面创建的连接,传递到下一个拦截器
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }

1.StreamAllocation 这里的是在RetryAndFollowUpInterceptor拦截器中构造的包含网络请求所有组件的StreamAllocation流分配对象,一步一步传递过来的。
2.HttpCodec对象用来编码request,解码response的 。
3.RealConnection 用来进行实际的io网络传输。
4.会将HttpCodec和RealConnection 传递给后面的拦截器使用。

StreamAllocation

首先,StreamAllocation的初始化在第一个拦截器RetryAndFollowUpInterceptor里面,

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

传入了三个参数,一个连接池,一个地址类,一个调用堆栈跟踪相关的。

在StreamAllocation构造函数中,主要是把这个三个参数保存为内部变量,供后面使用。
该构造器里面有两个重要的参数:
1.使用了Okhttp的连接池ConnectionPool
2.通过url创建了一个Address对象。

Okhttp连接池简单说明: 本篇只是对连接池做最简单的说明,内部的实现原理暂时不细讲。在Okhttp内部的连接池实现类为ConnectionPool,该类持有一个ArrayDeque队列作为缓存池,该队列里的元素为RealConnection(通过这个名字应该不难猜出RealConnection是来干嘛的)。该链接池在初始化OkhttpClient对象的时候由OkhttpClient的Builder类创建,并且ConnectionPool提供了put、get、evictAll等操作。但是Okhttp并没有直接对连接池进行获取,插入等操作;而是专门提供了一个叫Internal的抽象类来操作缓冲池:比如向缓冲池里面put一个RealConnection,从缓冲池get一个RealConnection对象,该类里面有一个public且为static的Internal类型的引用:

//抽象类
public abstract class Internal {
  public static Internal instance;
}1234

instance的初始化是在OkhttpClient的static语句块完成的:

static {
    Internal.instance = new Internal() {
       //省略部分代码
    };
  }

newStream()方法

主要做了如下工作:
1)从缓冲池ConnectionPool获取一个RealConnection对象,如果缓冲池里面没有就创建一个RealConnection对象并且放入缓冲池中,具体的说是放入ConnectionPool的ArrayDeque队列中。
2)获取RealConnection对象后并调用其connect(打开Socket链接)。下面具体分析:

public HttpCodec newStream(OkHttpClient client, boolean doExtensiveHealthChecks) {
    //1. 获取设置的连接超时时间,读写超时的时间,以及是否进行重连。 
    int connectTimeout = client.connectTimeoutMillis();
    int readTimeout = client.readTimeoutMillis();
    int writeTimeout = client.writeTimeoutMillis();
    boolean connectionRetryEnabled = client.retryOnConnectionFailure();

    try {
     // 2. 获取健康可用的连接
      RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
          writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);
     
     //3. 通过resultConnection初始化,对请求以及结果 编解码的类(分http 1.1 和http 2.0)。
     // 这里主要是初始化,在后面一个拦截器才用到这相关的东西。
      HttpCodec resultCodec = resultConnection.newCodec(client, this);

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

获取连接

findHealthyConnection()

 private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
      int writeTimeout, boolean connectionRetryEnabled, boolean doExtensiveHealthChecks)
      throws IOException {

   // 1. 加了个死循环,一直找可用的连接
    while (true) {
     
      // 2. 这里继续去挖掘,寻找连接
      RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
          connectionRetryEnabled);

     // 3. 连接池同步获取,上面找到的连接是否是一个新的连接,如果是的话,就直接返回了,就是我们需要找
    // 的连接了
      // If this is a brand new connection, we can skip the extensive health checks.
      synchronized (connectionPool) {
        if (candidate.successCount == 0) {
          return candidate;
        }
      }

      //4.  如果不是一个新的连接,那么通过判断,是否一个可用的连接。
      // 里面是通过Socket的一些方法进行判断的,有兴趣的,可以继续研究一下
      // Do a (potentially slow) check to confirm that the pooled connection is still good. If it
      // isn't, take it out of the pool and start again.
      if (!candidate.isHealthy(doExtensiveHealthChecks)) {
        noNewStreams();
        continue;
      }

      return candidate;
    }
  }

findConnection

/**
   * Returns a connection to host a new stream. This prefers the existing connection if it exists,
   * then the pool, finally building a new connection.
   */
  private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
      boolean connectionRetryEnabled) throws IOException {

    Route selectedRoute;
   
   // 1. 同步线程池,来获取里面的连接
    synchronized (connectionPool) {
        
         // 2.  异常的处理。做些判断,是否已经释放,是否编解码类为空,是否用户已经取消         if (released) throw new IllegalStateException("released");
         if (codec != null) throw new IllegalStateException("codec != null");
         if (canceled) throw new IOException("Canceled");
         
         // 3. 尝试用一下现在的连接,判断一下,是否有可用的连接。(使用已存在的连接)
         // Attempt to use an already-allocated connection.
          RealConnection allocatedConnection = this.connection;
         if (allocatedConnection != null && !allocatedConnection.noNewStreams) {
            return allocatedConnection;
          }
          
         // 4. 尝试在连接池中获取一个连接,get方法中会直接调用,注意最后一个参数为空
         // 里面是一个for循环,在连接池里面,寻找合格的连接
         // 而合格的连接会通过,StreamAllocation中的acquire方法,更新connection的值。(从缓存中获取)      
         // Attempt to get a connection from the pool.
         Internal.instance.get(connectionPool, address, this, null);
         if (connection != null) {
             return connection;
          }

          selectedRoute = route;
    }
    //5. 判断上面得到的线路,是否空,如果为空的,寻找一个可用的线路
    // 对于线路的选,可以深究一下这个RouteSeletor
    // 线路的选择,多ip的支持       if (selectedRoute == null) {
      selectedRoute = routeSelector.next();// 里面又个神奇的递归
    }

    RealConnection result;

    //6.  以上都不符合,创建一个连接
    synchronized (connectionPool) {
      if (canceled) throw new IOException("Canceled");
   
      // 7. 由于上面我们获取了一个线路,无论是新建的,或者已有的。
      // 我们通过这个线路,继续在连接池中寻找是否有可用的连接。
      // Now that we have an IP address, make another attempt at getting a connection from the pool.
      // This could match due to connection coalescing.
      Internal.instance.get(connectionPool, address, this, selectedRoute);
      if (connection != null) return connection;

      // 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;
      
      // 8. 如果前面这么寻找,都没在连接池中找打可用的连接,那么就新建一个
      result = new RealConnection(connectionPool, selectedRoute);
      acquire(result);
    }
    
    // 9. 这里就是就是连接的操作了,终于找到连接的正主了,这里会调用RealConnection的连接方法,进行连接操作。
    // 如果是普通的http请求,会使用Socket进行连接
    // 如果是https,会进行相应的握手,建立通道的操作。
    // 这里就不对里面的操作进行详细分析了,有兴趣可以在进去看看
    // Do TCP + TLS handshakes. This is a blocking operation.
    result.connect(connectTimeout, readTimeout, writeTimeout, connectionRetryEnabled);
    routeDatabase().connected(result.route());

    Socket socket = null;
    
   // 10. 最后就是同步加到 连接池里面了
    synchronized (connectionPool) {
      // Pool the connection.
      Internal.instance.put(connectionPool, result);

      // 最后加了一个多路复用的判断,这个是http2才有的
      // 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);

    return result;
  }

建立连接

建立连接是比较重要的一步了。如果是Https还有证书步骤

public void connect(
    int connectTimeout, int readTimeout, int writeTimeout, boolean connectionRetryEnabled) {
  if (protocol != null) throw new IllegalStateException("already connected");
// 线路的选择
  RouteException routeException = null;
  List connectionSpecs = route.address().connectionSpecs();
  ConnectionSpecSelector connectionSpecSelector = new ConnectionSpecSelector(connectionSpecs);

  if (route.address().sslSocketFactory() == null) {
    if (!connectionSpecs.contains(ConnectionSpec.CLEARTEXT)) {
      throw new RouteException(new UnknownServiceException(
          "CLEARTEXT communication not enabled for client"));
    }
    String host = route.address().url().host();
    if (!Platform.get().isCleartextTrafficPermitted(host)) {
      throw new RouteException(new UnknownServiceException(
          "CLEARTEXT communication to " + host + " not permitted by network security policy"));
    }
  }

// 连接开始
  while (true) {
    try {
    // 如果要求通道模式,建立通道连接,通常不是这种
      if (route.requiresTunnel()) {
        connectTunnel(connectTimeout, readTimeout, writeTimeout);
      } else {
      // 一般都走这条逻辑了,实际上很简单就是socket的连接
        connectSocket(connectTimeout, readTimeout);
      }
      // https的建立
      establishProtocol(connectionSpecSelector);
      break;
    } catch (IOException e) {
      closeQuietly(socket);
      closeQuietly(rawSocket);
      socket = null;
      rawSocket = null;
      source = null;
      sink = null;
      handshake = null;
      protocol = null;
      http2Connection = null;

      if (routeException == null) {
        routeException = new RouteException(e);
      } else {
        routeException.addConnectException(e);
      }

      if (!connectionRetryEnabled || !connectionSpecSelector.connectionFailed(e)) {
        throw routeException;
      }
    }
  }

  if (http2Connection != null) {
    synchronized (connectionPool) {
      allocationLimit = http2Connection.maxConcurrentStreams();
    }
  }
}

connectSocket

private void connectSocket(int connectTimeout, int readTimeout) throws IOException {
  Proxy proxy = route.proxy();
  Address address = route.address();

  // 根据代理类型处理socket,为true
  rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP
      ? address.socketFactory().createSocket()
      : new Socket(proxy);

  rawSocket.setSoTimeout(readTimeout);
  try {
    // 连接socket,之所以这样写是因为支持不同的平台
    /**
    * 里面实际上是  socket.connect(address, connectTimeout);
    *
    */
    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;
  }
  // 得到输入/输出流
  source = Okio.buffer(Okio.source(rawSocket));
  sink = Okio.buffer(Okio.sink(rawSocket));
}

如果使用的是https协议,并且配置有真实将会协议升级。

Https协议的建立 connectTls

如果使用的是https协议socket连接完成后还有一步,就是Tls的处理

private void connectTls(ConnectionSpecSelector connectionSpecSelector) throws IOException {
  Address address = route.address();
  SSLSocketFactory sslSocketFactory = address.sslSocketFactory();
  boolean success = false;
  SSLSocket sslSocket = null;
  try {
    // 在原来socket上加一层ssl
    // Create the wrapper over the connected socket.
    sslSocket = (SSLSocket) sslSocketFactory.createSocket(
        rawSocket, address.url().host(), address.url().port(), true /* autoClose */);

    // Configure the socket's ciphers, TLS versions, and extensions.
    ConnectionSpec connectionSpec = connectionSpecSelector.configureSecureSocket(sslSocket);
    if (connectionSpec.supportsTlsExtensions()) {
      Platform.get().configureTlsExtensions(
          sslSocket, address.url().host(), address.protocols());
    }

    // Force handshake. This can throw!
    sslSocket.startHandshake();
    Handshake unverifiedHandshake = Handshake.get(sslSocket.getSession());

    // Verify that the socket's certificates are acceptable for the target host.
    if (!address.hostnameVerifier().verify(address.url().host(), sslSocket.getSession())) {
      X509Certificate cert = (X509Certificate) unverifiedHandshake.peerCertificates().get(0);
      throw new SSLPeerUnverifiedException("Hostname " + address.url().host() + " not verified:"
          + "\n    certificate: " + CertificatePinner.pin(cert)
          + "\n    DN: " + cert.getSubjectDN().getName()
          + "\n    subjectAltNames: " + OkHostnameVerifier.allSubjectAltNames(cert));
    }

    // Check that the certificate pinner is satisfied by the certificates presented.
    address.certificatePinner().check(address.url().host(),
        unverifiedHandshake.peerCertificates());

    // Success! Save the handshake and the ALPN protocol.
    String maybeProtocol = connectionSpec.supportsTlsExtensions()
        ? Platform.get().getSelectedProtocol(sslSocket)
        : null;
    socket = sslSocket;
    source = Okio.buffer(Okio.source(socket));
    sink = Okio.buffer(Okio.sink(socket));
    handshake = unverifiedHandshake;
    protocol = maybeProtocol != null
        ? Protocol.get(maybeProtocol)
        : Protocol.HTTP_1_1;
    success = true;
  } catch (AssertionError e) {
    if (Util.isAndroidGetsocknameError(e)) throw new IOException(e);
    throw e;
  } finally {
    if (sslSocket != null) {
      Platform.get().afterHandshake(sslSocket);
    }
    if (!success) {
      closeQuietly(sslSocket);
    }
  }
}

CallServerInterceptor

 public Response intercept(Chain chain) throws IOException {
    // 省略部分代码
    // 获取HttpCodec 
    HttpCodec httpCodec = realChain.httpStream();
    // 省略部分代码
    Request request = realChain.request();
    //向服务器发送请求
    httpCodec.writeRequestHeaders(request);

    Response.Builder responseBuilder = null;
    // 检测是否有请求body
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {

      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
        httpCodec.flushRequest();
        //构建responseBuilder对象
        responseBuilder = httpCodec.readResponseHeaders(true);
      }

       //如果服务器允许发送请求body发送
      if (responseBuilder == null) {
        Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
        request.body().writeTo(bufferedRequestBody);
        bufferedRequestBody.close();
      } else if (!connection.isMultiplexed()) {
         //省略部分代码
      }
    }

    //结束请求
    httpCodec.finishRequest();

    //构建请求buidder对象
    if (responseBuilder == null) {
      responseBuilder = httpCodec.readResponseHeaders(false);
    }

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

    int code = response.code();
    if (forWebSocket && code == 101) {
      //省略部分代码
    } else {
      response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();
    }

    //省略部分代码

    return response;
  }

CallServerInterceptor的主要功能就是—向服务器发送请求,并最终返回Response对象供客户端使用。

总结

RetryAndFollowUpInterceptor:这个拦截器它的作用主要是负责请求的重定向操作,用于处理网络请求中,请求失败后的重试机制。
BridgeInterceptor:BridgeInterceptor负责在request阶段对请求头添加一些字段,在response阶段对响应进行一些gzip解压操作。
CacheInterceptor:用来实现响应缓存。比如获取到的 Response 带有 Date,Expires,Last-Modified,Etag 等 header,表示该 Response 可以缓存一定的时间,下次请求就可以不需要发往服务端,直接拿缓存的
ConnectInterceptor:ConnectInterceptor负责网络连接,其本质是复用连接池中socket连接。
CallServerInterceptor:CallServerInterceptor的主要功能就是—向服务器发送请求,并最终返回Response对象供客户端使用。

你可能感兴趣的:(Android,OkHttp)