美文网首页
Android - 剖析OKHttp(4)- 拦截器RetryA

Android - 剖析OKHttp(4)- 拦截器RetryA

作者: 杨0612 | 来源:发表于2020-11-06 15:21 被阅读0次

    源码分析基于 3.14.4

    RetryAndFollowUpInterceptor作用

    从名字就能看出,他是负责失败重试以及重定向。

    //RetryAndFollowUpInterceptor类中
    @Override public Response intercept(Chain chain) throws IOException {
     ......
      while (true) {
        ......
        try {
          response = realChain.proceed(request, transmitter, null);//1
          success = true;
        } catch (RouteException e) {//2
          if (!recover(e.getLastConnectException(), transmitter, false, request)) {
            throw e.getFirstConnectException();
          }
          continue;
        } catch (IOException e) {//3
          boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
          if (!recover(e, transmitter, requestSendStarted, request)) throw e;
          continue;
        } 
    
    
        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);//4
        ```
        if (followUp == null) {//6
            if (exchange != null && exchange.isDuplex()) {
               transmitter.timeoutEarlyExit();
            }
          return response;
        }
    
        ......
        RequestBody followUpBody = followUp.body();
        if (followUpBody != null && followUpBody.isOneShot()) {
          return response;
        }
        ......
        if (++followUpCount > MAX_FOLLOW_UPS) {///5
          throw new ProtocolException("Too many follow-up requests: " + followUpCount);
        }
    
        request = followUp;
        priorResponse = response;
      }
    }
    
    • 核心功能在intercept函数中;
    • 注释1:一般的拦截器都会有预处理,然后再丢给下一个拦截器处理,但是它没有,它直接丢给下一个拦截器了;
    • 注释2:如果发生RouteException(路由异常),通常是因为跟服务器没有建立连接,例如域名对应多个ip,其中一个ip连接失败,则重试另外的ip;
    • 注释3:如果发IOException,连接已经建立,在读写的过程中服务器发生了异常,例如down机了,则重试;;
    • 注释4:当不是发生 RouteException或IOException异常,则通过followUpRequest返回结果判断是否需要重试;
    • 注释5:限制重试次数为20次;
    • 注释6:当followUp为null,则表示返回结果正常,即返回结果;
    //RetryAndFollowUpInterceptor类中
    private Request followUpRequest(Response userResponse, @Nullable Route route) throws IOException {
        ......
        switch (responseCode) {
          case HTTP_PROXY_AUTH://1
            ......
            return client.proxyAuthenticator().authenticate(route, userResponse);
          case HTTP_UNAUTHORIZED://2
            return client.authenticator().authenticate(route, userResponse);
          ......
          case HTTP_MOVED_PERM://3
          case HTTP_MOVED_TEMP://4
            if (!client.followRedirects()) return null;
            String location = userResponse.header("Location");
            if (location == null) return null;
            HttpUrl url = userResponse.request().url().resolve(location);
            ......
            return requestBuilder.url(url).build();
    
          case HTTP_CLIENT_TIMEOUT://5
            ......
            return userResponse.request();
            ......
          default:
            return null;
        }
      }
    
    • 主要是根据服务器返回码判断是否需要重试;
    • 注释1、2:当返回码为401或者407,表示鉴权有问题,会回调client.authenticator().authenticate(route, userResponse)或者client.proxyAuthenticator().authenticate(route, userResponse),提供一次获取新验证码写入Request头的机会,接着开始重试;
    • 注释3、4:当返回码为301或者302,表示需要重定向,则用新的url构建Request开始重试;301或者302的响应头,带有Location,就是重定向的地址,例如Location:www.baidu.com
    • 注释5:返回码408,如果允许重试(client.retryOnConnectionFailure()为true),并且服务器没有返回Retry-After 延迟时间,则可以立即开始重试;
    • 301表示永久重定向,302表示临时重定向,408表示请求超时,401表示授权失败,407表示代理授权失败;

    总结:

    • RetryAndFollowUpInterceptor负责失败重试以及重定向;
    • RetryAndFollowUpInterceptor.intercept函数,内部是while循环处理,当正常返回结果则退出循环,否则重试;
    • 当发生RouteException或IOException或根据返回码,考虑需要重试;
    • 301表示永久重定向,302表示临时重定向,408表示请求超时,401表示授权失败,407表示代理授权失败;
    • 重试次数限制在20次;

    以上分析有不对的地方,请指出,互相学习,谢谢哦!

    相关文章

      网友评论

          本文标题:Android - 剖析OKHttp(4)- 拦截器RetryA

          本文链接:https://www.haomeiwen.com/subject/obhzvktx.html