OkHttp源码分析(三)-----------------截获器

承接上文

我们在在OkHttp源码分析(一)中分析过getResponseWithInterceptorChain()方法源码,其中设置了各种截获器,总结起来如下图所示:
这里写图片描述

源码分析

我们再来看一看getResponseWithInterceptorChain()方法的源码,观察截获器的相关操作

Response getResponseWithInterceptorChain() throws IOException {
   List<Interceptor> 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));
   //所有的截获器最终构建了一个chain
   Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
       originalRequest, this, eventListener, client.connectTimeoutMillis(),
       client.readTimeoutMillis(), client.writeTimeoutMillis());
   //最终执行proceed方法
   return chain.proceed(originalRequest);
 }

所有现在重要的是RealInterceptorChain#proceed方法,我们接着看

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {

    if (index >= interceptors.size()) throw new AssertionError();
    calls++;

    .........

    // 判断每一个截获器都有对应的处理,没有则创建RealInterceptorChain,即是创建当前的类,不断的迭代
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    //并执行当前的截获器的intercept方法
    Response response = interceptor.intercept(next);

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    .........

    return response;
  }

现在终于到执行到截获器中的intercept方法了,接下来会简要分析一下

RetryAndFollowUpInterceptor:失败重试及重定向时使用
  @Override 
  public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Call call = realChain.call();
    EventListener eventListener = realChain.eventListener();

    //实例化流分配,其实就是一个Socket管理类,管理着Connections、Streams、Calls三者之间的关系,
    //其中有我们所说的Socket自动选择最佳路径,拥有自动维护的连接池,减少握手次数
    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 {
        //又调用proceed方法,推进链中下一个节点
        response = realChain.proceed(request, streamAllocation, null, null);
        //若无异常则不用释放连接,后续判断
        releaseConnection = false;
      } catch (RouteException e) {
        //捕获到路由寻址异常,尝试恢复连接,若是还是没能连接成功,抛出异常
        if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
          throw e.getLastConnectException();
        }
        releaseConnection = false;
        continue;
      } catch (IOException e) {
        //连接关闭异常,说明请求没有被发送,否则请求已发出
        boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
        if (!recover(e, streamAllocation, requestSendStarted, request)) throw e;
        releaseConnection = false;
        continue;
      } finally {
        //综合以上结果,判断是否关闭连接
        if (releaseConnection) {
          streamAllocation.streamFailed(null);
          streamAllocation.release();
        }
      }


      if (priorResponse != null) {
        response = response.newBuilder()
            .priorResponse(priorResponse.newBuilder()
                    .body(null)
                    .build())
            .build();
      }
      //重定项,根据response重建request
      Request followUp = followUpRequest(response, streamAllocation.route());

      if (followUp == null) {
        if (!forWebSocket) {
          streamAllocation.release();
        }
        //如果不是重定向,返回response
        return response;
      }

      .........

      if (++followUpCount > MAX_FOLLOW_UPS) {
        //有最大次数限制20次
        streamAllocation.release();
        throw new ProtocolException("Too many follow-up requests: " + followUpCount);
      }

      ........... 

      //把重定向的请求赋值给request,以便再次进入循环执行
      //重定向功能默认是开启的,可以选择关闭,然后去实现自己的重定向功能:
      request = followUp;
      priorResponse = response;
    }
  }
BridgeInterceptor:负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应

其实说白了BridgeInterceptor就是在request阶段对请求头添加一些字段,在response阶段对响应进行一些GZIP解压操作。GZIP是使用非常普遍的数据压缩格式,或者说是一种文件格式,HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术,通常使用GZIP压缩技术压缩网页的内容,传输之后经过解压显示出来.这样主观的体现就是加载速度很快

 @Override 
 public Response intercept(Chain chain) throws IOException {
    /** 获取当前的请求*/
    Request userRequest = chain.request();
    Request.Builder requestBuilder = userRequest.newBuilder();
    /**注意,这是获得的请求是最原始的请求,没有请求头header,所以BridgeInterceptor截获器就是起这个作用*/
    RequestBody body = userRequest.body();
    if (body != null) {
      MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

     /**添加Content-Length、Transfer-Encoding、Host、Connection、Accept-Encoding、Range、Cookie、User-Agent*/
     .........      

    /** 获取网络响应,转换为用户友好的响应 */
    Response networkResponse = chain.proceed(requestBuilder.build());

    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

    Response.Builder responseBuilder = networkResponse.newBuilder()
        .request(userRequest);

    /** GZIP解压 */
    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();
  }
CacheInterceptor:负责读取缓存直接返回、更新缓存 详见HTTP缓存机制及原理
@Override 
public Response intercept(Chain chain) throws IOException {
    //读取候选缓存,从缓存中获得Response,但是不一定存在
    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()); 
    }

    // 根据策略,禁用网络,并且缓存无效,则直接报错
    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 {
      //若是前面两个都没有返回,则执行下一个拦截器
      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());
      }
    }

    // 接收到的网络结果,如果是code 304, 使用缓存,返回缓存结果(对比缓存)
    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();

        cache.trackConditionalCacheHit();
        cache.update(cacheResponse, response);
        return response;
      } else {
        closeQuietly(cacheResponse.body());
      }
    }

     //读取网络结果
    Response response = networkResponse.newBuilder()
        .cacheResponse(stripBody(cacheResponse))
        .networkResponse(stripBody(networkResponse))
        .build();

    // 将响应response进行缓存
    if (cache != null) {
      if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
        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;
  }
CallServerInterceptor:负责和服务器建立连接

建立连接实际上就是创建了一个 HttpCodec 对象

 @Override 
 public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    //StreamAllocation 上述过程中提到过是Socket管理类,这里只分析截获器,就不在向深处挖掘
    StreamAllocation streamAllocation = realChain.streamAllocation();
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    //获取realConnetion
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    RealConnection connection = streamAllocation.connection();
    //执行下一个拦截器
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }
CallServerInterceptor:负责向服务器发送请求数据、从服务器读取响应数据
 /**
   主干内容:
   1、向服务器发送 request header
   2、如果有 request body,就向服务器发送
   3、读取 response header,先构造一个 Response 对象
   4、如果有 response body,就在 3 的基础上加上 body 构造一个新的 Response 对象
 */
 @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());
    /** 1、向服务器发送 request header*/
    httpCodec.writeRequestHeaders(request);
    realChain.eventListener().requestHeadersEnd(realChain.call(), request);

    Response.Builder responseBuilder = null;
    /** 2、如果有 request body,就向服务器发送*/
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
      /**询问Server是否愿意接受数据*/ 
      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
        httpCodec.flushRequest();
        realChain.eventListener().responseHeadersStart(realChain.call());
        /**构建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) {
      realChain.eventListener().responseHeadersStart(realChain.call());
      responseBuilder = httpCodec.readResponseHeaders(false);
    }
    //3、读取 response header,先构造一个 Response 对象
    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    int code = response.code();

    ..........

    //4、如果有 response body,就在 3 的基础上加上 body 构造一个新的 Response 对象
    if (forWebSocket && code == 101) {
      response = response.newBuilder()
          .body(Util.EMPTY_RESPONSE)
          .build();
    } else {
      response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();
    }

    .........

    return response;
  }

猜你喜欢

转载自blog.csdn.net/qq_33768280/article/details/80764822
今日推荐