基本使用
okhttp是Square公司开源的一个非常便捷的轻量级第三方网络访问框架。它支持同步请求和异步请求。
Gradle依赖如下:
implementation 'com.squareup.okhttp3:okhttp:4.0.1'
异步请求
val url = "http://wwww.baidu.com"
val okHttpClient = OkHttpClient()
val request = Request.Builder()
.url(url)
.get()//默认就是GET请求
.build()
val call = okHttpClient.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.d(TAG, "onFailure: ");
}
override fun onResponse(call: Call, response: Response) {
Log.d(TAG, "onResponse: " + response.body?.string())
}
})
同步请求
val url = "http://wwww.baidu.com"
val okHttpClient = OkHttpClient()
val request = Request.Builder()
.url(url)
.get()
.build()
val call = okHttpClient.newCall(request)
val result = call.execute()//会阻塞
源码分析
OkHttpClient的创建,调用的是Builder,我们看下Builder的初始化
internal var dispatcher: Dispatcher = Dispatcher()// 分发器
internal var connectionPool: ConnectionPool = ConnectionPool()//连接池
internal val interceptors: MutableList = mutableListOf()// 拦截器
internal val networkInterceptors: MutableList = mutableListOf()// 网络拦截器
internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()//监听器工厂
internal var retryOnConnectionFailure = true//连接失败是否重试
internal var authenticator: Authenticator = Authenticator.NONE//本地身份验证
internal var followRedirects = true//http是否重定向
internal var followSslRedirects = true//ssl是否支持重定向
internal var cookieJar: CookieJar = CookieJar.NO_COOKIES //Cookie
internal var cache: Cache? = null // 缓存
internal var dns: Dns = Dns.SYSTEM //域名解析
internal var proxy: Proxy? = null //代理
internal var proxySelector: ProxySelector = ProxySelector.getDefault() ?: NullProxySelector()// 代理选择器
internal var proxyAuthenticator: Authenticator = Authenticator.NONE //代理身份验证
internal var socketFactory: SocketFactory = SocketFactory.getDefault() //socket 工厂
internal var sslSocketFactoryOrNull: SSLSocketFactory? = null // sslsocket工厂 用于https
internal var connectionSpecs: List = DEFAULT_CONNECTION_SPECS// 传输层版本和连接协议 TLS等
internal var protocols: List = DEFAULT_PROTOCOLS// 支持的协议
internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier //用于确认主机名
internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT //证书链
internal var certificateChainCleaner: CertificateChainCleaner? = null //证书确认
internal var callTimeout = 0 //调用超时时间
internal var connectTimeout = 10_000//连接超时时间
internal var readTimeout = 10_000 //读取超时时间
internal var writeTimeout = 10_000//写入超时时间
internal var pingInterval = 0 //// 长连接时命令间隔
Request的创建
open fun build(): Request {
return Request(
checkNotNull(url) { "url == null" },//请求地址
method,//请求方法
headers.build(),//请求头
body,//请求体
tags.toImmutableMap()
)
}
Request的创建用了构造者模式来创建,Request主要是对请求参数的封装
Call的创建,通过okHttpClient#newCall创建call
override fun newCall(request: Request): Call {
return RealCall.newRealCall(this, request, forWebSocket = false)
}
RealCall.kt
companion object {
fun newRealCall(
client: OkHttpClient,
originalRequest: Request,
forWebSocket: Boolean
): RealCall {
// Safely publish the Call instance to the EventListener.
return RealCall(client, originalRequest, forWebSocket).apply {
transmitter = Transmitter(client, this)
}
}
}
RealCall是针对OkHttpClient和Request的封装。Call的具体实现就是在RealCall。
RealCall中还定义了OkHttp的拦截器链,具体的作用后面会讲到。
发起异步请求,调用call#enqueue。实际调用的是Call的实现类RealCall的enqueue。
override fun enqueue(responseCallback: Callback) {
synchronized(this) {
check(!executed) { "Already Executed" }
executed = true
}
transmitter.callStart()
client.dispatcher.enqueue(AsyncCall(responseCallback))//分发器进行分发
}
client.dispatcher就是Dispatcher分发器,异步调用它的enqueue。
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
readyAsyncCalls.add(call)//将Call添加到异步准备队列
...
if (!call.get().forWebSocket) {
val existingCall = findExistingCallWithHost(call.host())
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
}
}
promoteAndExecute()//发起请求
}
发起同步请求,调用call#executed。实际调用的是Call的实现类RealCall的executed。
override fun execute(): Response {
synchronized(this) {
check(!executed) { "Already Executed" }
executed = true
}
transmitter.timeoutEnter()
transmitter.callStart()
try {
client.dispatcher.executed(this)
return getResponseWithInterceptorChain()//进行同步请求。会block线程
} finally {
client.dispatcher.finished(this)
}
}
Dispatcher分析
//支持的最大并发请求数量
@get:Synchronized var maxRequests = 64
set(maxRequests) {
require(maxRequests >= 1) { "max < 1: $maxRequests" }
synchronized(this) {
field = maxRequests
}
promoteAndExecute()
}
//每个主机的最大请求数量
@get:Synchronized var maxRequestsPerHost = 5
set(maxRequestsPerHost) {
require(maxRequestsPerHost >= 1) { "max < 1: $maxRequestsPerHost" }
synchronized(this) {
field = maxRequestsPerHost
}
promoteAndExecute()
}
//请求线程池
@get:Synchronized
@get:JvmName("executorService") val executorService: ExecutorService
get() {
if (executorServiceOrNull == null) {
executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
SynchronousQueue(), threadFactory("OkHttp Dispatcher", false))
}
return executorServiceOrNull!!
}
//将要运行的异步请求队列
private val readyAsyncCalls = ArrayDeque()
//正在运行的异步请求队列
private val runningAsyncCalls = ArrayDeque()
//正在运行的同步请求队列
private val runningSyncCalls = ArrayDeque()
Dispatcher#promoteAndExecute
private fun promoteAndExecute(): Boolean {
assert(!Thread.holdsLock(this))
val executableCalls = mutableListOf()
val isRunning: Boolean
synchronized(this) {
val i = readyAsyncCalls.iterator()//将要运行的异步请求队列
while (i.hasNext()) {//遍历
val asyncCall = i.next()
if (runningAsyncCalls.size >= this.maxRequests) break //超过了最大并发请求数则结束
if (asyncCall.callsPerHost().get() >= this.maxRequestsPerHost) continue //找过了这个主机最大的连接数,遍历下一个
i.remove()//将asyncCall从准备队列中移除
asyncCall.callsPerHost().incrementAndGet()//主机连接数+1
executableCalls.add(asyncCall)//执行请求的集合
runningAsyncCalls.add(asyncCall)//将asyncCall添加到正在运行的队列
}
isRunning = runningCallsCount() > 0
}
for (i in 0 until executableCalls.size) {//遍历执行请求的集合
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)//执行请求
}
return isRunning
}
异步请求执行完之后会回调Dispatcher#finished,处理队列中的任务,如果没有任务可以处理那么空闲callback会回调
private fun finished(calls: Deque, call: T) {
val idleCallback: Runnable?
//省略部分代码
val isRunning = promoteAndExecute()//进行任务处理
if (!isRunning && idleCallback != null) {
idleCallback.run()//回调空闲CalBack
}
}
我们分析下AsyncCall,AsyncCall实现了Runnable接口。我们看下run方法
override fun run() {
threadName("OkHttp ${redactedUrl()}") {
var signalledCallback = false
transmitter.timeoutEnter()
try {
val response = getResponseWithInterceptorChain()//得到拦截器链
signalledCallback = true
responseCallback.onResponse(this@RealCall, response)//返回结果回调
} catch (e: IOException) {
if (signalledCallback) {
//省略部分代码
} else {
responseCallback.onFailure(this@RealCall, e)//异常回调
}
} finally {
client.dispatcher.finished(this)//这里会调用Dispatcher的finished,继续处理队列其他的任务
}
}
}
Dispatcher中具体的开始任务是通过AsyncCall#executeOn,代码的核心是调用ExecutorService#execute,通过线程池发起异步请求
fun executeOn(executorService: ExecutorService) {
//省略部分代码
try {
executorService.execute(this)//发起异步请求
success = true
} catch (e: RejectedExecutionException) {
//省略部分代码
responseCallback.onFailure(this@RealCall, ioException)
} finally {
if (!success) {
client.dispatcher.finished(this) // 异常情况,回调finished
}
}
}
下面我们分析RealCall#getResponseWithInterceptorChain
fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
val interceptors = mutableListOf()
interceptors += client.interceptors//自定义的拦截器
interceptors += RetryAndFollowUpInterceptor(client)//重定向拦截器
interceptors += BridgeInterceptor(client.cookieJar)//桥拦截器
interceptors += CacheInterceptor(client.cache)//缓存连接器
interceptors += ConnectInterceptor//连接拦截器
if (!forWebSocket) {
interceptors += client.networkInterceptors//自定义的网络拦截器
}
interceptors += CallServerInterceptor(forWebSocket)//请求服务器拦截器
val chain = RealInterceptorChain(interceptors, transmitter, null, 0, originalRequest, this,
client.connectTimeoutMillis, client.readTimeoutMillis, client.writeTimeoutMillis)//得到拦截器链
var calledNoMoreExchanges = false
try {
val response = chain.proceed(originalRequest)//进行任务处理,开始链式调用
if (transmitter.isCanceled) {
response.closeQuietly()
throw IOException("Canceled")
}
return response
} catch (e: IOException) {
calledNoMoreExchanges = true
throw transmitter.noMoreExchanges(e) as Throwable
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null)
}
}
}
RealInterceptorChain实现了Interceptor.Chain
interface Chain {
fun request(): Request
@Throws(IOException::class)
fun proceed(request: Request): Response
fun connection(): Connection?
fun call(): Call
fun connectTimeoutMillis(): Int
fun withConnectTimeout(timeout: Int, unit: TimeUnit): Chain
fun readTimeoutMillis(): Int
fun withReadTimeout(timeout: Int, unit: TimeUnit): Chain
fun writeTimeoutMillis(): Int
fun withWriteTimeout(timeout: Int, unit: TimeUnit): Chain
}
核心的处理逻辑是process,简化后的代码如下
@Throws(IOException::class)
fun proceed(request: Request, transmitter: Transmitter, exchange: Exchange?): Response {
if (index >= interceptors.size) throw AssertionError()
calls++
val next = RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout)//创建新的拦截链,链中的拦截器集合index+1
val interceptor = interceptors[index]得到下一个拦截器
@Suppress("USELESS_ELVIS")
val response = interceptor.intercept(next) ?: throw NullPointerException(//执行Interceptor#intercept
"interceptor $interceptor returned null")
return response
}
每当我们调用process的时候都会调用拦截链的下一个Interceptor。这里用的是责任链模式。
下面我们分析下具体的拦截器
RetryAndFollowUpInterceptor的作用进行连接失败重新连接,以及重定向
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val realChain = chain as RealInterceptorChain
val transmitter = realChain.transmitter()
var followUpCount = 0
var priorResponse: Response? = null
while (true) {
transmitter.prepareToConnect(request)
if (transmitter.isCanceled) {
throw IOException("Canceled")
}
var response: Response
var success = false
try {
response = realChain.proceed(request, transmitter, null)//处理下一个Intercepter
success = true
} catch (e: RouteException) {
//尝试通过路由进行连接失败。该请求不会被发送
if (!recover(e.lastConnectException, transmitter, false, request)) {
throw e.firstConnectException
}
continue
} catch (e: IOException) {
//尝试与服务器通信失败。 该请求可能已发送
val requestSendStarted = e !is ConnectionShutdownException
if (!recover(e, transmitter, requestSendStarted, request)) throw e
continue
} finally {
}
if (priorResponse != null) {
response = response.newBuilder()//创建一个响应体为空的Response
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build()
}
val exchange = response.exchange
val route = exchange?.connection()?.route()
val followUp = followUpRequest(response, route)//重定向,如果不为空则返回重定向的Request
if (followUp == null) {//不需要重定向,直接返回response
if (exchange != null && exchange.isDuplex) {
transmitter.timeoutEarlyExit()
}
return response
}
val followUpBody = followUp.body
if (followUpBody != null && followUpBody.isOneShot()) {
return response
}
response.body?.closeQuietly()
if (transmitter.hasExchange()) {
exchange?.detachWithViolence()
}
if (++followUpCount > MAX_FOLLOW_UPS) {//超过了最大的重定向次数会抛出异常,这里MAX_FOLLOW_UPS是20
throw ProtocolException("Too many follow-up requests: $followUpCount")
}
request = followUp//把重定向的请求赋值给request,以便再次进入循环执行
priorResponse = response
}
}
followUpRequest如果有重定向拿到重定向的request否则返回null,根据响应码分别进行处理请求
private fun followUpRequest(userResponse: Response, route: Route?): Request? {
val responseCode = userResponse.code
val method = userResponse.request.method
when (responseCode) {
HTTP_PROXY_AUTH -> { //407 代理认证
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_UNAUTHORIZED -> return client.authenticator.authenticate(route, userResponse)//401未经过认证
HTTP_PERM_REDIRECT//308, HTTP_TEMP_REDIRECT //307-> {
//如果收到307或308状态代码以响应GET或HEAD以外的请求,则用户代理不得自动重定向请求
if (method != "GET" && method != "HEAD") {
return null
}
return buildRedirectRequest(userResponse, method)
}
HTTP_MULT_CHOICE//300, HTTP_MOVED_PERM//301, HTTP_MOVED_TEMP//302, HTTP_SEE_OTHER//303 -> {
return buildRedirectRequest(userResponse, method)
}
HTTP_CLIENT_TIMEOUT -> {//408 超时
// 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.
//应用程序层指示我们不要重试请求
return null
}
val requestBody = userResponse.request.body
if (requestBody != null && requestBody.isOneShot()) {
return null
}
val priorResponse = userResponse.priorResponse
if (priorResponse != null && priorResponse.code == HTTP_CLIENT_TIMEOUT) {
// We attempted to retry and got another timeout. Give up.
return null
}
if (retryAfter(userResponse, 0) > 0) {
return null
}
return userResponse.request
}
HTTP_UNAVAILABLE -> {//503
val priorResponse = userResponse.priorResponse
if (priorResponse != null && priorResponse.code == HTTP_UNAVAILABLE) {
// 我们试图重试并再次超时。 放弃
return null
}
if (retryAfter(userResponse, Integer.MAX_VALUE) == 0) {
// 收到指示,立即重试
return userResponse.request
}
return null
}
else -> return null
}
}
BridgeInterceptor的作用是对请求头和响应头进行处理
override fun intercept(chain: Interceptor.Chain): Response {
val userRequest = chain.request()
val requestBuilder = userRequest.newBuilder()
val body = userRequest.body
if (body != null) {
//处理响应头
val contentType = body.contentType()
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString())//增加Content-Type
}
val contentLength = body.contentLength()
if (contentLength != -1L) {
requestBuilder.header("Content-Length", contentLength.toString())
requestBuilder.removeHeader("Transfer-Encoding")
} else {
requestBuilder.header("Transfer-Encoding", "chunked")
requestBuilder.removeHeader("Content-Length")
}
}
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", userRequest.url.toHostHeader())//增加Host
}
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive")
}
var transparentGzip = false
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true
requestBuilder.header("Accept-Encoding", "gzip")//添加gzip压缩支持
}
val cookies = cookieJar.loadForRequest(userRequest.url)//处理Cookie
if (cookies.isNotEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies))
}
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", userAgent)增加User-Agent
}
val networkResponse = chain.proceed(requestBuilder.build())//执行下一个Intercepter
cookieJar.receiveHeaders(userRequest.url, networkResponse.headers)//处理Cookie
val responseBuilder = networkResponse.newBuilder()
.request(userRequest)
//gzip解压处理
if (transparentGzip &&
"gzip".equals(networkResponse.header("Content-Encoding"), ignoreCase = true) &&
networkResponse.promisesBody()) {
val responseBody = networkResponse.body
if (responseBody != null) {
val gzipSource = GzipSource(responseBody.source())
val strippedHeaders = networkResponse.headers.newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build()
responseBuilder.headers(strippedHeaders)
val contentType = networkResponse.header("Content-Type")
responseBuilder.body(RealResponseBody(contentType, -1L, gzipSource.buffer()))
}
}
return responseBuilder.build()
}
CacheInterceptor的作用是读取缓存和更新缓存的操作
override fun intercept(chain: Interceptor.Chain): Response {
val cacheCandidate = cache?.get(chain.request())//读取缓存
val now = System.currentTimeMillis()
val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute()//创建缓存策略
val networkRequest = strategy.networkRequest
val cacheResponse = strategy.cacheResponse
cache?.trackResponse(strategy)
if (cacheCandidate != null && cacheResponse == null) {
// 缓存不可用,将它关闭
cacheCandidate.body?.closeQuietly()
}
// 不使用网络,又没有缓存的直接报错,并创建返回的Response错误码是504
if (networkRequest == null && cacheResponse == null) {
return Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(HTTP_GATEWAY_TIMEOUT)
.message("Unsatisfiable Request (only-if-cached)")
.body(EMPTY_RESPONSE)
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
}
// 如果没有网络,则使用缓存
if (networkRequest == null) {
return cacheResponse!!.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build()
}
var networkResponse: Response? = null
try {
networkResponse = chain.proceed(networkRequest)//进行下一个Intercepter
} finally {
if (networkResponse == null && cacheCandidate != null) {
cacheCandidate.body?.closeQuietly()
}
}
if (cacheResponse != null) {
if (networkResponse?.code == HTTP_NOT_MODIFIED) {//如果返回的是304,直接返回缓存
val response = cacheResponse.newBuilder()
.headers(combine(cacheResponse.headers, networkResponse.headers))
.sentRequestAtMillis(networkResponse.sentRequestAtMillis)
.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis)
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build()
networkResponse.body!!.close()
cache!!.trackConditionalCacheHit()
cache.update(cacheResponse, response)
return response
} else {
cacheResponse.body?.closeQuietly()
}
}
//使用网络请求
val response = networkResponse!!.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build()
if (cache != null) {
if (response.promisesBody() && CacheStrategy.isCacheable(response, networkRequest)) {
// Offer this request to the cache.
val cacheRequest = cache.put(response)//更新缓存
return cacheWritingResponse(cacheRequest, response)
}
//PATCH、PUT、DELETE、MOVE不需要缓存
if (HttpMethod.invalidatesCache(networkRequest.method)) {
try {
cache.remove(networkRequest)
} catch (_: IOException) {
// The cache cannot be written.
}
}
}
return response
}
ConnectInterceptor的作用与服务器进行连接
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
val request = realChain.request() //得到Request
val transmitter = realChain.transmitter()
val doExtensiveHealthChecks = request.method != "GET"
val exchange = transmitter.newExchange(chain, doExtensiveHealthChecks)//创建socket进行连接
return realChain.proceed(request, transmitter, exchange)
}
OkHttp创建网络连接的时序图如下:
CallServerInterceptor的作用是发送请求和接收数据
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
val exchange = realChain.exchange()
val request = realChain.request()
val requestBody = request.body
val sentRequestMillis = System.currentTimeMillis()
exchange.writeRequestHeaders(request)//写入请求头
var responseHeadersStarted = false
var responseBuilder: Response.Builder? = null
if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
//如果请求中存在“Expect:100-continue”标头,请在发送请求主体之前等待“HTTP / 1.1 100 Continue”响应。
// 如果我们没有得到,请返回我们得到的内容(例如4xx响应),而不发送请求主体。
if ("100-continue".equals(request.header("Expect"), ignoreCase = true)) {
exchange.flushRequest()
responseHeadersStarted = true
exchange.responseHeadersStart()
responseBuilder = exchange.readResponseHeaders(true)
}
if (responseBuilder == null) {//写入请求体
if (requestBody.isDuplex()) {
// Prepare a duplex body so that the application can send a request body later.
exchange.flushRequest()
val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()
requestBody.writeTo(bufferedRequestBody)
} else {
// Write the request body if the "Expect: 100-continue" expectation was met.
val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
requestBody.writeTo(bufferedRequestBody)
bufferedRequestBody.close()
}
} else {
exchange.noRequestBody()
if (!exchange.connection()!!.isMultiplexed) {
// If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
// from being reused. Otherwise we're still obligated to transmit the request body to
// leave the connection in a consistent state.
exchange.noNewExchangesOnConnection()
}
}
} else {
exchange.noRequestBody()
}
if (requestBody == null || !requestBody.isDuplex()) {
exchange.finishRequest()
}
if (!responseHeadersStarted) {
exchange.responseHeadersStart()
}
if (responseBuilder == null) {
responseBuilder = exchange.readResponseHeaders(false)!!//读取响应头
}
var response = responseBuilder
.request(request)
.handshake(exchange.connection()!!.handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
//读取响应体
var code = response.code
if (code == 100) {
//即使我们没有请求,但是服务器发送了100-continue。
//再次尝试读取实际的回复
response = exchange.readResponseHeaders(false)!!
.request(request)
.handshake(exchange.connection()!!.handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
code = response.code
}
exchange.responseHeadersEnd(response)
response = if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
response.newBuilder()
.body(EMPTY_RESPONSE)
.build()
} else {
response.newBuilder()
.body(exchange.openResponseBody(response))
.build()
}
if ("close".equals(response.request.header("Connection"), ignoreCase = true) ||
"close".equals(response.header("Connection"), ignoreCase = true)) {
exchange.noNewExchangesOnConnection()
}
if ((code == 204 || code == 205) && response.body?.contentLength() ?: -1L > 0L) {
throw ProtocolException(
"HTTP $code had non-zero Content-Length: ${response.body?.contentLength()}")
}
return response
}
总结下,OkHttp网络拦截链在Intercepter的process之前是处理Request,在process是对Response处理。
整理的流程图如下: