OkHttp3源码解析04-失败重连

回到RealCall的getResponse方法

Response getResponse(Request request, boolean forWebSocket) throws IOException {
// Copy body metadata to the appropriate request headers.
RequestBody body = request.body();
if (body != null) {
  Request.Builder requestBuilder = request.newBuilder();

  MediaType contentType = body.contentType();
  if (contentType != null) {
    requestBuilder.header("Content-Type", contentType.toString());
  }

  long contentLength = body.contentLength();
  if (contentLength != -1) {
    requestBuilder.header("Content-Length", Long.toString(contentLength));
    requestBuilder.removeHeader("Transfer-Encoding");
  } else {
    requestBuilder.header("Transfer-Encoding", "chunked");
    requestBuilder.removeHeader("Content-Length");
  }

  request = requestBuilder.build();
}

// Create the initial HTTP engine. Retries and redirects need new engine for each attempt.
engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);

int followUpCount = 0;
while (true) {
  if (canceled) {
    engine.releaseStreamAllocation();
    throw new IOException("Canceled");
  }

  boolean releaseConnection = true;
  try {
    engine.sendRequest();
    engine.readResponse();
    releaseConnection = false;
  } catch (RequestException e) {
    // The attempt to interpret the request failed. Give up.
    throw e.getCause();
  } catch (RouteException e) {
    // The attempt to connect via a route failed. The request will not have been sent.
    HttpEngine retryEngine = engine.recover(e.getLastConnectException(), null);
    if (retryEngine != null) {
      releaseConnection = false;
      engine = retryEngine;
      continue; //进入下一个while遍历
    }
    // Give up; recovery is not possible.
    throw e.getLastConnectException();
  } catch (IOException e) {
    // An attempt to communicate with a server failed. The request may have been sent.
    HttpEngine retryEngine = engine.recover(e, null);
    if (retryEngine != null) {
      releaseConnection = false;
      engine = retryEngine;
      continue; //进入下一个while遍历
    }

    // Give up; recovery is not possible.
    throw e;
  } finally {
    // We're throwing an unchecked exception. Release any resources.
    if (releaseConnection) {
      StreamAllocation streamAllocation = engine.close();
      streamAllocation.release();
    }
  }

  //...
  if (followUp == null) {
    if (!forWebSocket) {
      engine.releaseStreamAllocation();
    }
    return response;
  }

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

  //...
  engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null,
  response);
}
}

可以看到在catch里,会调用engine.recover方法

public HttpEngine recover(IOException e, Sink requestBodyOut) {
    if (!streamAllocation.recover(e, requestBodyOut)) {
      return null;
    }

    if (!client.retryOnConnectionFailure()) {
      return null;
    }

    StreamAllocation streamAllocation = close();

    // For failure recovery, use the same route selector with a new connection.
    return new HttpEngine(client, userRequest, bufferRequestBody, callerWritesRequestBody,
        forWebSocket, streamAllocation, (RetryableSink) requestBodyOut, priorResponse);
}

可以看到,这里重新创建一个HttpEngine并返回

最终,只要成功,就会返回response

if (followUp == null) {
    if (!forWebSocket) {
    engine.releaseStreamAllocation();
    }
    return response;
}

如果超过20次都失败,那么就抛出ProtocolException异常

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

总结

OkHttp的失败重连机制,就是发送request或读取Response的时候,出现crash,就会重新创建一个HttpEngine重新执行,最多执行20次,如果还失败,会抛出ProtocolException异常

猜你喜欢

转载自blog.csdn.net/ethanco/article/details/78335206
今日推荐