天天看点

OkHttp3源码分析-RetryAndFollowUpInterceptor

RetryAndFollowUpInterceptor

RetryAndFollowUpInterceptor

有两个功能,一个是重试,一个是重定向。如果

Call

被取消,

RetryAndFollowUpInterceptor

将抛出异常。

我们来一起分析一下。

public final class RetryAndFollowUpInterceptor implements Interceptor {
    @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);
    	this.streamAllocation = streamAllocation;
        ......
    }
}
           

上面代码主要是创建

StreamAllocation

对象。后面还会再做分析,它用于协调

Connection

Stream

Call

public final class RetryAndFollowUpInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        ......
        int followUpCount = 0;
    	Response priorResponse = null;
    	while (true) {
      		if (canceled) {
        		streamAllocation.release();
        		throw new IOException("Canceled");
      		}
            ·····
        }
    }
}
           

判断是否取消了请求,如果是的就就直接抛出异常。

public final class RetryAndFollowUpInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        ......
        int followUpCount = 0;
    	Response priorResponse = null;
    	while (true) {
          ......
      	  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.getFirstConnectException();
            }
            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();
            }
          }
          ······
        }
    }
}
           

循环处理请求。

  1. 尝试着从责任链中获取响应

    Response

  2. 如果出现异常

    RouteException

    IOException

    尝试着去恢复,并继续。
public final class RetryAndFollowUpInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        ......
        int followUpCount = 0;
    	Response priorResponse = null;
    	while (true) {
            ......
      		if (priorResponse != null) {
        		response = response.newBuilder()
            	    .priorResponse(priorResponse.newBuilder()
                        .body(null)
                        .build())
            	    .build();
      		}
            ......
        }
    }
}
           

如果上次的请求的

Response

不为

null

,添加到当前的

Response

中。

public final class RetryAndFollowUpInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        ......
        int followUpCount = 0;
    	Response priorResponse = null;
    	while (true) {
            ......
      		Request followUp;
      		try {
        		followUp = followUpRequest(response, streamAllocation.route());
      		} catch (IOException e) {
        		streamAllocation.release();
        		throw e;
      		}
             if (followUp == null) {
        		streamAllocation.release();
        		return response;
      		}
            ......
        }
    }
}
           

调用

followUpRequest

获取下次请求

Request

followUpRequest

中包括重定向,认证错误等处理。如果

followUp

null

说明不能进行下次重试或者重定向了,直接返回。

public final class RetryAndFollowUpInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        ......
        int followUpCount = 0;
    	Response priorResponse = null;
    	while (true) {
            ......
      	  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;
        }
    }
}
           

先是关闭

response

body

接着就是判断

followUpCount

是否超过了最大的

MAX_FOLLOW_UPS

,超过了直接抛出异常。

接着判断

followUp

body

是否是

UnrepeatableRequestBody

的实例,如果是,直接抛出异常。

接着通过

sameConnection

方法判断相应的

response

followUp

是否是同一个连接,如果是重定向二者不会相同,需要重新创建

StreamAllocation

最后是赋值到相应的变量。继续循环。