OkHttp3源码解析--拦截器RetryAndFollowUpInterceptor

看一下OkHttp内置的第一个拦截器RetryAndFollowUpInterceptor:

RetryAndFollowUpInterceptor

public final class RetryAndFollowUpInterceptor implements Interceptor {private static final int MAX_FOLLOW_UPS = 20;  //最大的重定向次数
  private final OkHttpClient client;             //前面创建的OkHttpClient对象
  private final boolean forWebSocket;            //是否是webSocket
  private StreamAllocation streamAllocation;     //流分配器,在这个拦截器中初始化
  private Object callStackTrace;
  private volatile boolean canceled;             //请求是否被取消了
  
  //主要是传入进来OkHttpClient对象
  public RetryAndFollowUpInterceptor(OkHttpClient client, boolean forWebSocket) {
    this.client = client;
    this.forWebSocket = forWebSocket;
  }
  
  @Override public Response intercept(Chain chain) throws IOException {
    
    //***************获取需要的对象Request,RealInterceptorChain,Call,StreamAllocation****************
    Request request = chain.request();                            //之前我们创建的Request对象
    RealInterceptorChain realChain = (RealInterceptorChain) chain;//创建的下一个拦截器链
    Call call = realChain.call();                                 //我们之前创建的RealCall
    EventListener eventListener = realChain.eventListener();
    //创建了一个StreamAllocation对象,持有全局的连接池,Address对象,Call对象
    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.
      if (priorResponse != null) {
        response = response.newBuilder()
            .priorResponse(priorResponse.newBuilder()
                    .body(null)
                    .build())
            .build();
      }
      
      
      //**********************解析回复的code,如果请求失败,进行重定向*******************
      //解析response的code,判断response的类型,看是否请求成功。
      Request followUp = followUpRequest(response);
      //如果请求成功,返回followUp Request为null
      if (followUp == null) {
        if (!forWebSocket) {
          streamAllocation.release();
        }
        //请求成功,返回这个response
        return response;
      }
      //请求不成功,这个response关闭,释放资源。
      closeQuietly(response.body());
      //followUpCount加1后判断是否大于MAX_FOLLOW_UPS
      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());
      }
      //看response的服务器地址和followUp Request的url对比,看地址是否相同,这涉及是否可以连接复用。
      if (!sameConnection(response, followUp.url())) {
        streamAllocation.release();
        //重新创建一个StreamAllocation对象
        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对象
      request = followUp;
      //记录Response
      priorResponse = response;
    }
    
    /**
   * 取消执行请求
   */
  public void cancel() {
    canceled = true;
    StreamAllocation streamAllocation = this.streamAllocation;
    if (streamAllocation != null) streamAllocation.cancel();
  }
  //返回是否被取消
  public boolean isCanceled() {
    return canceled;
  }}

上述过程中出现了StreamAllocation对象的创建,以及调用release方法等。下面看一下StreamAllocation这个类:

StreamAllocation

public final class StreamAllocation {
  public final Address address;                  //请求地址信息
  private RouteSelector.Selection routeSelection;//路由选择器
  private Route route;                           //路由
  private final ConnectionPool connectionPool;   //全局连接池,在OkHttpClient对象创建过程中已经创建完成
  public final Call call;                        //请求Call
  public final EventListener eventListener;
  private final Object callStackTrace;// State guarded by connectionPool.
  private final RouteSelector routeSelector;
  private int refusedStreamCount;
  private RealConnection connection;            //真实建立的连接
  private boolean reportedAcquired;
  private boolean released;                     //资源是否被释放
  private boolean canceled;                     //请求是否被取消
  private HttpCodec codec;                      //Http 流
  
  public StreamAllocation(ConnectionPool connectionPool, Address address, Call call,
      EventListener eventListener, Object callStackTrace) {
    this.connectionPool = connectionPool;
    this.address = address;
    this.call = call;
    this.eventListener = eventListener;
    this.routeSelector = new RouteSelector(address, routeDatabase(), call, eventListener);
    this.callStackTrace = callStackTrace;
  }
  //释放资源
  public void release() {
    Socket socket;
    Connection releasedConnection;
    synchronized (connectionPool) {
      releasedConnection = connection;
      socket = deallocate(false, true, false);//会关闭connection对象
      if (connection != null) releasedConnection = null;
    }
    closeQuietly(socket);
    if (releasedConnection != null) {
      eventListener.connectionReleased(call, releasedConnection);
    }
  }
}

后续会针对StreamAllocation专门进行更深入的介绍。

重定向功能是否开启,在创建OkHttpClient的时候可以设置:

new OkHttpClient().newBuilder()
                  .followRedirects(false)  //禁制OkHttp的重定向操作,我们自己处理重定向
                  .followSslRedirects(false)//https的重定向也自己处理

简单进行流程总结:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值