RetryAndFollowUpInterceptor

263 阅读2分钟

宏观流程

@Override public Response intercept(Chain chain) throws IOException {
    。。。
    while (true) {
    。。。
      try {
        response = realChain.proceed(request, streamAllocation, null, null);
      }
    。。。
    if(满足条件){
        return response;
    }
    。。。
      //不满足条件,一顿操作,赋值再来!
      request = followUp;
      priorResponse = response;
    }
  }

源码解读

@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的创建位置
    streamAllocation = new StreamAllocation(client.connectionPool(), createAddress(request.url()),
        call, eventListener, callStackTrace);

    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(), 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, 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是用来保存前一个Resposne的,这里可以看到将前一个Response和当前的Resposne
      //结合在一起了,对应的场景是,当获得Resposne后,发现需要重定向,则将当前Resposne设置给priorResponse,再执行一遍流程,
      //直到不需要重定向了,则将priorResponse和Resposne结合起来。
      if (priorResponse != null) {
        response = response.newBuilder()
            .priorResponse(priorResponse.newBuilder()
                    .body(null)
                    .build())
            .build();
      }
      //判断是否需要重定向,如果需要重定向则返回一个重定向的Request,没有则为null
      Request followUp = followUpRequest(response);

      if (followUp == null) {
        //不需要重定向
        if (!forWebSocket) {
          //是WebSocket,释放
          streamAllocation.release();
        }
        //返回response
        return response;
      }
      //需要重定向,关闭响应流
      closeQuietly(response.body());
      //重定向次数++,并且小于最大重定向次数MAX_FOLLOW_UPS(20)
      if (++followUpCount > MAX_FOLLOW_UPS) {
        streamAllocation.release();
        throw new ProtocolException("Too many follow-up requests: " + followUpCount);
      }
      //是UnrepeatableRequestBody, 刚才看过也就是是流类型,没有被缓存,不能重定向
      if (followUp.body() instanceof UnrepeatableRequestBody) {
        streamAllocation.release();
        throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
      }
      //判断是否相同,不然重新创建一个streamConnection
      if (!sameConnection(response, followUp.url())) {
        streamAllocation.release();
        streamAllocation = new StreamAllocation(client.connectionPool(),
            createAddress(followUp.url()), call, eventListener, callStackTrace);
      } 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. 通过RealInterceptorChain,再调用下一个拦截器;

  3. 收到结果之后,做异常处理,判断是否重连或者重定向,或者返回结果。(后置拦截)

参考: