Okhttp容错机制的坑

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhangteng22/article/details/52237839
OKHttp内部是做了失败从连的操作的,那么我就来简单看下失败重连的相关逻辑。

从源码RetryAndFollowUpInterceptor#intercept方法说起

因为是失败从连,所以我们要看cacth相关部分的代码,代码如下:

①
catch (RouteException e)
{
     // The attempt to connect via a route failed. The request will not have been sent. 即连接网络超时
      if (!recover(e.getLastConnectException(), true, request))
       throw e.getLastConnectException();
    releaseConnection = false;
    continue;
}



上面的关键之处在于recover(e.getLastConnectException(), true, request),接下来分析recover(e.getLastConnectException(), true, request)

②
/**
 * Report and attempt to recover from a failure to communicate with a server. Returns true if
 * {@code e} is recoverable, or false if the failure is permanent. Requests with a body can only
 * be recovered if the body is buffered.
 */
private boolean recover(IOException e, boolean routeException, Request userRequest)
{
 streamAllocation.streamFailed(e); 
// The application layer has forbidden retries.OkHttp的retryOnConnectionFailure默认值是true
if (!client.retryOnConnectionFailure())
 return false;
 // We can't send the request body again.即超时了
if (!routeException && userRequest.body() instanceof UnrepeatableRequestBody)
 return false;
// This exception is fatal.
if (!isRecoverable(e, routeException))
return false;
// No more routes to attempt.
if (!streamAllocation.hasMoreRoutes())
return false;
// For failure recovery, use the same route selector with a new connection.</code>
return true;
}



根据调用者recover(e.getLastConnectException(), true, request)request传递的值为true

1、如果client.retryOnConnectionFailure没有配置过那么默认值是true,就会走if (!isRecoverable(e, routeException))分支,接着分析isRecoverable方法

③
private boolean isRecoverable(IOException e, boolean routeException)
{
   // If there was a protocol problem, don't recover.
  if (e instanceof ProtocolException)
  {
    return false;
   }
        
   // If there was an interruption don't recover, but if there was a timeout connecting to a route
   // we should try the next route (if there is one).
  if (e instanceof InterruptedIOException)
   {
    return e instanceof SocketTimeoutException && routeException;
   }
        
    // Look for known client-side or negotiation errors that are unlikely to be fixed by trying
   // again with a different route.
  if (e instanceof SSLHandshakeException)
  {
      // If the problem was a CertificateException from the X509TrustManager,
     // do not retry.
      if (e.getCause() instanceof CertificateException)
    {
      return false;
      }
  }
  if (e instanceof SSLPeerUnverifiedException)
  {
     // e.g. a certificate pinning error.
     return false;
  }
        
 // An example of one we might want to retry with a different route is a problem connecting to a
 // proxy and would manifest as a standard IOException. Unless it is one we know we should not
 // retry, we return true and try a new route.
 return true;
}



根据分析最终返回了return e instanceof SocketTimeoutException && routeException;该值为true,那么②将返回true,①将继续continue,进行了重连

2、如果client.retryOnConnectionFailure配置了false那么②会返回false,那么①的catch中if (!recover(e.getLastConnectException(), true, request))会返回true然后紧接着会抛出异常,程序并不进行二次重连

因此:如果不设置retryOnConnectionFailure那么Okhttp会自动重连,会导致网络不好的情况下怀疑自己设置的超时时间没有其作用,设置该值后转包分析确实没有进行了重连,由于当时没有保存截图此次就不贴图了。

限于水平有限,不知其中分析的是否正确,还望指正。Okhttp3源码工程


展开阅读全文

没有更多推荐了,返回首页