overridefunintercept(chain: Interceptor.Chain): Response { val realChain = chain as RealInterceptorChain var request = chain.request val call = realChain.call var followUpCount = 0 var priorResponse: Response? = null var newExchangeFinder = true var recoveredFailures = listOf<IOException>() while (true) {//开启轮询 //1、构建一个ExchangeFinder call.enterNetworkInterceptorExchange(request, newExchangeFinder)//
var response: Response var closeActiveExchange = true try { if (call.isCanceled()) { throw IOException("Canceled") }
try { //2、运行下一个把拦截器,并拿到请求响应结果 response = realChain.proceed(request)//拿到响应结果 newExchangeFinder = true } catch (e: RouteException) { // The attempt to connect via a route failed. The request will not have been sent. //3 判断发生的RouteException是否回复 if (!recover(e.lastConnectException, call, request, requestSendStarted = false)) {// throw e.firstConnectException.withSuppressed(recoveredFailures) } else { recoveredFailures += e.firstConnectException } newExchangeFinder = false continue//再次轮询 } catch (e: IOException) { // An attempt to communicate with a server failed. The request may have been sent. //4 判断发生的IOException是否回复 if (!recover(e, call, request, requestSendStarted = e !is ConnectionShutdownException)) { throw e.withSuppressed(recoveredFailures) } else { recoveredFailures += e } newExchangeFinder = false continue//再次轮询 }
// Attach the prior response if it exists. Such responses never have a body. //5 根据上一次的Response,构建一个新的response if (priorResponse != null) {//之前的Response response = response.newBuilder() .priorResponse(priorResponse.newBuilder() .body(null) .build()) .build() }
val exchange = call.interceptorScopedExchange //6、根据响应码创建一个新的Request请求 val followUp = followUpRequest(response, exchange)//重定向 //7、上一步构建的Request为空,则不再继续下去,直接把的Response返回 if (followUp == null) { if (exchange != null && exchange.isDuplex) { call.timeoutEarlyExit() } closeActiveExchange = false return response } //8. 如果构建的Request的body为一次性的请求,也同样直接返回Response val followUpBody = followUp.body if (followUpBody != null && followUpBody.isOneShot()) { closeActiveExchange = false return response }
response.body?.closeQuietly() //9、如果重定向次数大于20次,也直接抛出异常,否次进入下次轮询也就是重试 if (++followUpCount > MAX_FOLLOW_UPS) { throw ProtocolException("Too many follow-up requests: $followUpCount") }
overridefunintercept(chain: Interceptor.Chain): Response { val realChain = chain as RealInterceptorChain var request = chain.request val call = realChain.call var followUpCount = 0 var priorResponse: Response? = null var newExchangeFinder = true var recoveredFailures = listOf<IOException>() while (true) {//开启轮询 //1、构建一个ExchangeFinder call.enterNetworkInterceptorExchange(request, newExchangeFinder)// //... } }
overridefunintercept(chain: Interceptor.Chain): Response { val realChain = chain as RealInterceptorChain var request = chain.request val call = realChain.call var followUpCount = 0 var priorResponse: Response? = null var newExchangeFinder = true var recoveredFailures = listOf<IOException>() while (true) {//开启轮询 //1、构建一个ExchangeFinder call.enterNetworkInterceptorExchange(request, newExchangeFinder)//
var response: Response var closeActiveExchange = true try { if (call.isCanceled()) { throw IOException("Canceled") }
try { //2、运行下一个把拦截器,并拿到请求响应结果 response = realChain.proceed(request)//拿到响应结果 newExchangeFinder = true } catch (e: RouteException) { // The attempt to connect via a route failed. The request will not have been sent. //3 判断发生的RouteException是否回复 if (!recover(e.lastConnectException, call, request, requestSendStarted = false)) {// throw e.firstConnectException.withSuppressed(recoveredFailures) } else { recoveredFailures += e.firstConnectException } newExchangeFinder = false continue//再次轮询 } catch (e: IOException) { // An attempt to communicate with a server failed. The request may have been sent. //4 判断发生的IOException是否回复 if (!recover(e, call, request, requestSendStarted = e !is ConnectionShutdownException)) { throw e.withSuppressed(recoveredFailures) } else { recoveredFailures += e } newExchangeFinder = false continue//再次轮询 } //... } finally { call.exitNetworkInterceptorExchange(closeActiveExchange) } } }
val retryRoute = retryRoute() if (retryRoute != null) { // Lock in the route because retryRoute() is racy and we don't want to call it twice. nextRouteToTry = retryRoute returntrue }
// If we have a routes left, use 'em. if (routeSelection?.hasNext() == true) returntrue
// If we haven't initialized the route selector yet, assume it'll have at least one route. val localRouteSelector = routeSelector ?: returntrue
// If we do have a route selector, use its routes. return localRouteSelector.hasNext() }
privatefunfollowUpRequest(userResponse: Response, exchange: Exchange?): Request? { val route = exchange?.connection?.route() val responseCode = userResponse.code
val method = userResponse.request.method when (responseCode) { HTTP_PROXY_AUTH -> { val selectedProxy = route!!.proxy if (selectedProxy.type() != Proxy.Type.HTTP) { throw ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy") } return client.proxyAuthenticator.authenticate(route, userResponse) }
HTTP_CLIENT_TIMEOUT -> { // 408's are rare in practice, but some servers like HAProxy use this response code. The // spec says that we may repeat the request without modifications. Modern browsers also // repeat the request (even non-idempotent ones.) if (!client.retryOnConnectionFailure) { // The application layer has directed us not to retry the request. returnnull }
val requestBody = userResponse.request.body if (requestBody != null && requestBody.isOneShot()) { returnnull } val priorResponse = userResponse.priorResponse if (priorResponse != null && priorResponse.code == HTTP_CLIENT_TIMEOUT) { // We attempted to retry and got another timeout. Give up. returnnull }
if (retryAfter(userResponse, 0) > 0) { returnnull }
return userResponse.request }
HTTP_UNAVAILABLE -> { val priorResponse = userResponse.priorResponse if (priorResponse != null && priorResponse.code == HTTP_UNAVAILABLE) { // We attempted to retry and got another timeout. Give up. returnnull }
if (retryAfter(userResponse, Integer.MAX_VALUE) == 0) { // specifically received an instruction to retry without delay return userResponse.request }
returnnull }
HTTP_MISDIRECTED_REQUEST -> { // OkHttp can coalesce HTTP/2 connections even if the domain names are different. See // RealConnection.isEligible(). If we attempted this and the server returned HTTP 421, then // we can retry on a different connection. val requestBody = userResponse.request.body if (requestBody != null && requestBody.isOneShot()) { returnnull }
if (exchange == null || !exchange.isCoalescedConnection) { returnnull }