【Android】okHttp源码之RetryAndFollowUpInterceptor

RetryAndFollowUpInterceptor

RetryAndFollowUpInterceptor是用于失败重试及重定向的拦截器。在okHttp中,无论是调用同步execute方法或者是异步enqueue方法最终都会调用响应拦截链方法——getResponseWithInterceptorChain()。该方法主要是建立各种拦截器,RetryAndFollowUpInterceptor就是其中一种

getResponseWithInterceptorChain方法的源码如下图所示:

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    //失败重试和重定向拦截器
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    //桥接拦截器:用于处理请求和返回的拦截器
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //缓存拦截器:负责把网络请求的响应写入缓存和从缓存中读取响应
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //与服务端建立连接,并获取通向服务端的输入流和输出流
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    //向服务端发送客户端的请求数据并封装服务端返回的response
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    boolean calledNoMoreExchanges = false;
    try {
      Response response = chain.proceed(originalRequest);
      if (transmitter.isCanceled()) {
        closeQuietly(response);
        throw new IOException("Canceled");
      }
      return response;
    } catch (IOException e) {
      calledNoMoreExchanges = true;
      throw transmitter.noMoreExchanges(e);
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null);
      }
    }
  }

如上代码所示,拦截器最终都会加入到一个 List链表中,然后通过RealInterceptorChain封装拦截器的相关信息,注意0这个数字,这个参数对应着RealInterceptorChain构造函数的index,是List链表的角标,主要用于判断是否超出List的大小或者取出List中的对应的拦截器等。RealInterceptorChain的引用是接口Chain,chain.proceed(originalRequest)是调用的RealInterceptorChain的proceed方法,proceed方法如下所示:

  @Override public Response proceed(Request request) throws IOException {
    return proceed(request, transmitter, exchange);
  }

  public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
      throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    if (this.exchange != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

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

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    if (response.body() == null) {
      throw new IllegalStateException(
          "interceptor " + interceptor + " returned a response with no body");
    }

    return response;
  }

值得分析的是如下几行代码

	if (index >= interceptors.size()) throw new AssertionError();//1

	// Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);//2
    Interceptor interceptor = interceptors.get(index);//3
    Response response = interceptor.intercept(next);//4
  • 第1行代码,如果索引index大于等于拦截器数量,则抛出异常。
  • 第2行代码,封装下一个拦截链对象,这里指的是BridgeInterceptor拦截器
  • 第3行代码,获取拦截器对象,这里是第一个拦截器RetryAndFollowUpInterceptor
  • 然后执行RetryAndFollowUpInterceptor拦截器的intercept方法,并将封装BridgeInterceptor拦截器的对象传递给intercept方法

所以接下来分析RetryAndFollowUpInterceptor拦截器的intercept方法

  @Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Transmitter transmitter = realChain.transmitter();

    int followUpCount = 0;
    Response priorResponse = null;
    while (true) {
      transmitter.prepareToConnect(request);

      if (transmitter.isCanceled()) {
        throw new IOException("Canceled");
      }

      Response response;
      boolean success = false;
      try {
        response = realChain.proceed(request, transmitter, null);
        success = true;
      } catch (RouteException e) {
        // The attempt to connect via a route failed. The request will not have been sent.
        if (!recover(e.getLastConnectException(), transmitter, false, request)) {
          throw e.getFirstConnectException();
        }
        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, transmitter, requestSendStarted, request)) throw e;
        continue;
      } finally {
        // The network call threw an exception. Release any resources.
        if (!success) {
          transmitter.exchangeDoneDueToException();
        }
      }

      // 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();
      }

      Exchange exchange = Internal.instance.exchange(response);
      Route route = exchange != null ? exchange.connection().route() : null;
      Request followUp = followUpRequest(response, route);

      if (followUp == null) {
        if (exchange != null && exchange.isDuplex()) {
          transmitter.timeoutEarlyExit();
        }
        return response;
      }

      RequestBody followUpBody = followUp.body();
      if (followUpBody != null && followUpBody.isOneShot()) {
        return response;
      }

      closeQuietly(response.body());
      if (transmitter.hasExchange()) {
        exchange.detachWithViolence();
      }

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

      request = followUp;
      priorResponse = response;
    }
  }

暂时不分析里面的内容,里面有行如下代码:

response = realChain.proceed(request, transmitter, null);

注意到这里realChain是之前将BridgeInterceptor拦截器封装到RealInterceptorChain对象的引用,所以这其实是一个递归,格式如下:

public Response proceed(){
	Response response = intercept();
	return response;
	
}

public Response intercept(){
	Response response = proceed();
	return response;
}
发布了107 篇原创文章 · 获赞 142 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/u013293125/article/details/95101197