OkHttp
是Android开发中十分罕用的一个网络申请库了,它反对HTTP1、HTTP2等多种协定,是咱们日常开发中十分给力的帮手。本篇文章基于OkHttp
4.9.0版本代码,从OkHttp
的创立开始,探索OkHttp是如何发动一次网络申请的。如果你有急躁看完,置信你会对OkHttp
有了一个粗浅的理解。如果感觉太长不看的话,看一下总结也是不错的呢(手动滑稽)。
OkHttpClient
应用OkHttp
的第一步,天然都是创立OkHttpClient
了:
OkHttpClient client = new OkHttpClient();
通过构造方法进入,看看这个OkHttpClient
到底是什么:
constructor() : this(Builder()) //默认结构 传入Builder实例
class Builder constructor() {
internal var dispatcher: Dispatcher = Dispatcher()//调度器
internal var connectionPool: ConnectionPool = ConnectionPool()//连接池
internal val interceptors: MutableList<Interceptor> = mutableListOf()//整体流程拦截器
internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()//网络申请拦截器
//流程监听器
internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
internal var retryOnConnectionFailure = true//申请失败是否主动重试
internal var authenticator: Authenticator = Authenticator.NONE//服务器认证设置
internal var followRedirects = true//是否重定向
internal var followSslRedirects = true//是否能够从HTTP重定向到HTTPS
internal var cookieJar: CookieJar = CookieJar.NO_COOKIES//Cookie策略,是否保留Cookie
internal var cache: Cache? = null//缓存配置
internal var dns: Dns = Dns.SYSTEM//Dns配置
internal var proxy: Proxy? = null//代理配置
internal var proxySelector: ProxySelector? = null//代理选择器
internal var proxyAuthenticator: Authenticator = Authenticator.NONE//代理服务器认证设置
internal var socketFactory: SocketFactory = SocketFactory.getDefault()//socket配置
internal var sslSocketFactoryOrNull: SSLSocketFactory? = null//https socket配置
internal var x509TrustManagerOrNull: X509TrustManager? = null
internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS//反对协定配置
internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier//域名校验
internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT//证书链
internal var certificateChainCleaner: CertificateChainCleaner? = null
internal var callTimeout = 0//申请超时配置 0代表不会超时
internal var connectTimeout = 10_000//连贯超时
internal var readTimeout = 10_000//读取超时
internal var writeTimeout = 10_000//写入超时
internal var pingInterval = 0//针对HTTP2和web socket的ping距离
internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE
internal var routeDatabase: RouteDatabase? = null
//...
能够看出OkHttpClient
实例就是个配置类,当理论发动申请的时候,会采纳用户设置的配置。采纳了Builder模式
的设计,让用户更不便的配置这一系列参数,灵便的结构较多的配置。
Request
根底的申请结构类,根本应用:
Request request = new Request.Builder()
.url(ENDPOINT)
.build();
Request
类用来形容单次申请的参数信息等,蕴含域名、申请形式、申请头、申请体等一系列信息。通过Builder
咱们能够链式调用,比拟优雅的配置这一系列信息。Request
类和OkHttpClient
类一样,实质是一个形容对象。
Call
申请创立实现,就能够调用OkHttpClient
来发动一次申请了,咱们须要通过OkHttpClient
的实例办法来发动一次申请:
Call call = client.newCall(request);
Call
是一个接口,定义如下:
interface Call : Cloneable {
/** 返回原始的申请信息 */
fun request(): Request
/** 立刻发动一次申请 同步办法 不能在主线程间接调用 */
@Throws(IOException::class)
fun execute(): Response
/** 发动一次异步申请 */
fun enqueue(responseCallback: Callback)
/** 勾销申请 */
fun cancel()
/** 是否被执行过 */
fun isExecuted(): Boolean
/** 是否被勾销了 */
fun isCanceled(): Boolean
/** 申请超时配置策略 */
fun timeout(): Timeout
/** clone这个Call */
public override fun clone(): Call
fun interface Factory {
fun newCall(request: Request): Call
}
}
OkHttpClient
实现的newCall
办法会创立一个RealCall
实例,RealCall
是利用和网络层的一个连贯桥,它保留了OkHttpClient
的援用和原始申请信息。咱们须要通过观察它的实现来追踪网络申请流程。
enqueue
override fun enqueue(responseCallback: Callback) {
//CAS判断是否曾经被执行了
check(executed.compareAndSet(false, true)) { "Already Executed" }
//申请开始告诉
callStart()
//创立异步申请入申请队列
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
异步申请办法会创立一个AsyncCall
,并调用OkHttpClient
配置的Dispatcher
解决此申请。
inner class AsyncCall(
private val responseCallback: Callback
) : Runnable
AsyncCall
实现了Runnable
接口,最终会被调度器的线程池进行执行,具体后续再来剖析。
execute
override fun execute(): Response {
//CAS判断是否曾经被执行了
check(executed.compareAndSet(false, true)) { "Already Executed" }
timeout.enter()//申请超时计时
callStart()//申请开始告诉
try {
client.dispatcher.executed(this)//应用调度器退出申请队列
return getResponseWithInterceptorChain()//申请责任链创立
} finally {
client.dispatcher.finished(this)//调度器完结申请
}
}
调用了execute
之后申请会被退出同步申请队列,而后创立响应责任链发动申请。申请实现会从调度器中移除本次申请。
getResponseWithInterceptorChain
重点来了,OkHttp发动一次申请都须要进行的办法,代码如下:
@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
val interceptors = mutableListOf<Interceptor>()
interceptors += client.interceptors//用户配置的拦截器
interceptors += RetryAndFollowUpInterceptor(client)//重连 重定向拦截器
interceptors += BridgeInterceptor(client.cookieJar)//构建申请和响应根本信息
interceptors += CacheInterceptor(client.cache)//缓存配置解决
interceptors += ConnectInterceptor//连贯拦截器 这里真正开始发动连贯
if (!forWebSocket) {
interceptors += client.networkInterceptors//网络拦截器
}
//执行流操作(写出申请体、取得响应数据) 负责向服务器发送申请数据、从服务器读取响应数据
//进行http申请报文的封装与申请报文的解析
interceptors += CallServerInterceptor(forWebSocket)
//创立责任链
val chain = RealInterceptorChain(
call = this,
interceptors = interceptors,
index = 0,
exchange = null,
request = originalRequest,
connectTimeoutMillis = client.connectTimeoutMillis,
readTimeoutMillis = client.readTimeoutMillis,
writeTimeoutMillis = client.writeTimeoutMillis
)
var calledNoMoreExchanges = false
try {
//执行责任链
val response = chain.proceed(originalRequest)
if (isCanceled()) {
response.closeQuietly()
throw IOException("Canceled")
}
return response//返回申请后果
} catch (e: IOException) {
calledNoMoreExchanges = true
throw noMoreExchanges(e) as Throwable
} finally {
if (!calledNoMoreExchanges) {
noMoreExchanges(null)
}
}
}
getResponseWithInterceptorChain
办法会按肯定的程序构建拦截器列表,这里用到了责任链模式
,解决完拦截器列表后,会创立拦截器责任链
,拦截器会按程序顺次调用,解决实现之后,再将返回信息返回给用户。
cancel
override fun cancel() {
if (canceled) return // 曾经被勾销 则返回
canceled = true
exchange?.cancel()//勾销io操作
connectionToCancel?.cancel()//敞开socket连贯
eventListener.canceled(this)//事件告诉
}
一次申请的勾销其实就是勾销了后续的IO操作和断开连接,而后进行事件告诉。因为调用此办法的时候连贯和IO可能还未开始,所以须要进行判空。
RealInterceptorChain
通过追踪一次同步申请的发动,咱们会发现最终会创立一个RealInterceptorChain
实例,并调用了其proceed
办法,接下来就来追踪其代码,看看外部到底是如何实现的。
@Throws(IOException::class)
override fun proceed(request: Request): Response {
check(index < interceptors.size)//查看下标越界
calls++
if (exchange != null) {
check(exchange.finder.sameHostAndPort(request.url)) {
"network interceptor ${interceptors[index - 1]} must retain the same host and port"
}
check(calls == 1) {
"network interceptor ${interceptors[index - 1]} must call proceed() exactly once"
}
}
// 下一个须要执行的拦截器,index+1
val next = copy(index = index + 1, request = request)
val interceptor = interceptors[index]
//调用拦截器的intercept办法,传入下一个责任链
@Suppress("USELESS_ELVIS")
val response = interceptor.intercept(next) ?: throw NullPointerException(
"interceptor $interceptor returned null")
if (exchange != null) {
check(index + 1 >= interceptors.size || next.calls == 1) {
"network interceptor $interceptor must call proceed() exactly once"
}
}
check(response.body != null) { "interceptor $interceptor returned a response with no body" }
return response
}
proceed
的办法也不简单,外面有一系列的检测办法,外围代码其实只有几行,大抵逻辑如下:
- 1、数组下标+1,取出下一个拦截器,而后复制并创立新的责任链
- 2、获取以后下标的拦截器
-
3、调用以后拦截器的
intercept
办法,并传入下一个拦截器责任链实例为什么能够链式调用上来呢?这里能够看一下
Interceptor
的接口定义fun interface Interceptor { @Throws(IOException::class) fun intercept(chain: Chain): Response }
Interceptor
只有一个办法,实现了intercept
办法后须要调用传递进来的Chain
,下面咱们曾经晓得了这是下一个拦截器。调用了chain.proceed办法返回Response
,将逻辑交由下一个拦截器解决。
Dispatcher
再回过头看异步申请,下面咱们能够晓得,一次异步申请最终是调用了dispatcher.enqueue
的办法,那么Dispatcher
负责了什么呢?
Dispatcher
次要负责异步申请的执行逻辑。Dispatcher
中能够定义maxRequests
来治理最大并发申请数量,maxRequestsPerHost
来确定单个host的最大并发申请数量。
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
//退出队列
readyAsyncCalls.add(call)
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
if (!call.call.forWebSocket) {
//找到此host存在的其余call
val existingCall = findExistingCallWithHost(call.host)
//如果找到了 复用其余call的计数器
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
}
}
//理论的去执行
promoteAndExecute()
}
调用了enqueue
办法后,会先上锁,而后在异步队列readyAsyncCalls
中退出此申请,再查看以后申请的host有无其余call,找到了,则复用其余call的申请计数器。最初走到promoteAndExecute
去执行。
private fun promoteAndExecute(): Boolean {
this.assertThreadDoesntHoldLock()
val executableCalls = mutableListOf<AsyncCall>()
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 //单个host申请下限,跳过此申请
i.remove()
asyncCall.callsPerHost.incrementAndGet()//cas 计数
executableCalls.add(asyncCall)//退出可执行的队列
runningAsyncCalls.add(asyncCall)//退出正在执行的队列
}
isRunning = runningCallsCount() > 0//标记是否正在执行
}
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)//执行申请
}
return isRunning
}
promoteAndExecute
办法会遍历异步申请队列,如果以后并发申请数量下限了,则会跳出,不执行任何申请。如果一个host的并发申请数量达到了下限,会跳过此申请。最初,为能够执行的申请进行调用。如果用户没有自行设置线程池,则Dispatcher
外部会创立一个的线程池用来执行异步网络申请。
fun executeOn(executorService: ExecutorService) {
client.dispatcher.assertThreadDoesntHoldLock()
var success = false
try {
//应用传入的线程池来执行
executorService.execute(this)
success = true
} catch (e: RejectedExecutionException) {
val ioException = InterruptedIOException("executor rejected")
ioException.initCause(e)
noMoreExchanges(ioException)
responseCallback.onFailure(this@RealCall, ioException)
} finally {
if (!success) {
//申请失败了也要告诉dispatcher
client.dispatcher.finished(this) // This call is no longer running!
}
}
}
下面我也说过了,AsyncCall
自身实现了Runable
接口,这里被执行之后,会调用run
办法,执行外部逻辑,具体逻辑和同步申请的逻辑基本一致,这里就不再赘述。申请实现后,不论后果成功失败,都会调用Dispatcher
的finished
办法。
internal fun finished(call: AsyncCall) {
call.callsPerHost.decrementAndGet()//cas 计数
finished(runningAsyncCalls, call)
}
private fun <T> finished(calls: Deque<T>, call: T) {
val idleCallback: Runnable?
synchronized(this) {
//从队列中移除当前任务
if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!")
idleCallback = this.idleCallback
}
//尝试执行其余工作
val isRunning = promoteAndExecute()
if (!isRunning && idleCallback != null) {
idleCallback.run()//如果以后闲置 进行告诉
}
}
finished
办法被调用后会从申请队列中移除以后申请,再尝试执行残余的申请。Dispatcher
外部也保护了同步申请队列,当同步申请实现之后也会走相似的逻辑。
RetryAndFollowUpInterceptor
这个拦截器用来进行谬误重试和重定向。拦截器外部是一个死循环。
try {
response = realChain.proceed(request)
newExchangeFinder = true
} catch (e: RouteException) {
// The attempt to connect via a route failed. The request will not have been sent.
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.
if (!recover(e, call, request, requestSendStarted = e !is ConnectionShutdownException)) {
throw e.withSuppressed(recoveredFailures)
} else {
recoveredFailures += e
}
newExchangeFinder = false
continue
}
网络申请的异样会被catch,而后会判断是否要从新进行申请。如果能失常走上来,则会对重定向相干进行判断,创立对应的申请。
ExchangeFinder
这个类在RetryAndFollowUpInterceptor
中调用call.enterNetworkInterceptorExchange(request, newExchangeFinder)后被创立。这个类用来在RealConnectionPool
连接池中找到一个以后申请可用的RealConnection
,而后开启连贯,进行接下来的IO操作。
ConnectInterceptor
这个拦截器会对指定的服务器关上连贯,而后执行其余的拦截器
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
val exchange = realChain.call.initExchange(chain)//初始化Exchange
val connectedChain = realChain.copy(exchange = exchange)//为之后的责任链传入Exchange
return connectedChain.proceed(realChain.request)
}
这个拦截器会调用RealCall
的initExchange
办法,并把以后的责任链传递过过来。
internal fun initExchange(chain: RealInterceptorChain): Exchange {
synchronized(this) {
check(expectMoreExchanges) { "released" }
check(!responseBodyOpen)
check(!requestBodyOpen)
}
val exchangeFinder = this.exchangeFinder!!
//用之前RetryAndFollowUpInterceptor传入的finder寻找编码器
val codec = exchangeFinder.find(client, chain)
//采纳对应的编码器创立Exchange
val result = Exchange(this, eventListener, exchangeFinder, codec)
this.interceptorScopedExchange = result
this.exchange = result
synchronized(this) {
this.requestBodyOpen = true
this.responseBodyOpen = true
}
if (canceled) throw IOException("Canceled")
return result
}
initExchange
里会应用ExchangeFinder
来寻找一个ExchangeCodec
,这是一个网络申请的编码器,针对不同的协定会采纳不同的形式来进行编码传输。
fun find(
client: OkHttpClient,
chain: RealInterceptorChain
): ExchangeCodec {
try {
//寻找一个衰弱的连贯
val resultConnection = findHealthyConnection(
connectTimeout = chain.connectTimeoutMillis,
readTimeout = chain.readTimeoutMillis,
writeTimeout = chain.writeTimeoutMillis,
pingIntervalMillis = client.pingIntervalMillis,
connectionRetryEnabled = client.retryOnConnectionFailure,
doExtensiveHealthChecks = chain.request.method != "GET"
)
//创立对应的编码器
return resultConnection.newCodec(client, chain)
} catch (e: RouteException) {
trackFailure(e.lastConnectException)
throw e
} catch (e: IOException) {
trackFailure(e)
throw RouteException(e)
}
}
ExchangeFinder
的find办法会去尝试找到一个与服务器之间的连贯。追踪findHealthyConnection
代码咱们会发现它外部是一个死循环,一直的调用findConnection
办法去寻找一个可用的连贯。findConnection
的代码就比拟长了,这里就不贴出来了。大略的逻辑就是优先从连接池中找连贯,如果没有找到可用的连贯,则会创立一个RealConnection
对象,存入缓存池中。
RealConnection
RealConnection
是OkHttp理论建设连贯的中央。通过connect
办法建设与服务器的链接。通过追踪源码咱们会发现RealConnection
底层还是通过Socket
建设连贯的。
@Throws(IOException::class)
private fun connectSocket(
connectTimeout: Int,
readTimeout: Int,
call: Call,
eventListener: EventListener
) {
val proxy = route.proxy
val address = route.address
val rawSocket = when (proxy.type()) {
Proxy.Type.DIRECT, Proxy.Type.HTTP -> address.socketFactory.createSocket()!!
else -> Socket(proxy)
}
this.rawSocket = rawSocket
eventListener.connectStart(call, route.socketAddress, proxy)
rawSocket.soTimeout = readTimeout
try {
//针对不同的平台进行适配
Platform.get().connectSocket(rawSocket, route.socketAddress, connectTimeout)
} catch (e: ConnectException) {
throw ConnectException("Failed to connect to ${route.socketAddress}").apply {
initCause(e)
}
}
try {
//应用OkIO开启io
source = rawSocket.source().buffer()
sink = rawSocket.sink().buffer()
} catch (npe: NullPointerException) {
if (npe.message == NPE_THROW_WITH_NULL) {
throw IOException(npe)
}
}
}
CallServerInterceptor
这是所有拦截器中的最初一个拦截器。在这个拦截器里会进行IO操作与服务器交互。OkHttp底层应用了OkIO
来进行IO操作。
@Throws(IOException::class)
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()
var invokeStartEvent = true
var responseBuilder: Response.Builder? = null
var sendRequestException: IOException? = null
try {
//写申请头 最终会调用具体的ExchangeCodec去实现
exchange.writeRequestHeaders(request)
if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
//遇到HTTP/1.1 中约定的Expect: 100-continue 会间接发动申请
if ("100-continue".equals(request.header("Expect"), ignoreCase = true)) {
exchange.flushRequest()//发送申请报文
responseBuilder = exchange.readResponseHeaders(expectContinue = true)//读取响应头
exchange.responseHeadersStart()//事件告诉
invokeStartEvent = false
}
if (responseBuilder == null) {
if (requestBody.isDuplex()) {
//针对HTTP2协定的双工申请体 先发送申请头
exchange.flushRequest()
val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()
requestBody.writeTo(bufferedRequestBody)//写入申请体
} else {
val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
requestBody.writeTo(bufferedRequestBody)//写入申请体
bufferedRequestBody.close()
}
} else {
//没有申请体
exchange.noRequestBody()
if (!exchange.connection.isMultiplexed) {
exchange.noNewExchangesOnConnection()
}
}
} else {
//没有申请体
exchange.noRequestBody()
}
if (requestBody == null || !requestBody.isDuplex()) {
exchange.finishRequest()//完结申请写入并发送
}
} catch (e: IOException) {
if (e is ConnectionShutdownException) {
throw e // No request was sent so there's no response to read.
}
if (!exchange.hasFailure) {
throw e // Don't attempt to read the response; we failed to send the request.
}
sendRequestException = e
}
try {
if (responseBuilder == null) {
//读取响应头
responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
if (invokeStartEvent) {
//事件告诉
exchange.responseHeadersStart()
invokeStartEvent = false
}
}
//构建Response
var response = responseBuilder
.request(request)
.handshake(exchange.connection.handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
var code = response.code
if (code == 100) {
// Server sent a 100-continue even though we did not request one. Try again to read the
// actual response status.
responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
if (invokeStartEvent) {
exchange.responseHeadersStart()
}
//如果code 是100则从新读取
response = responseBuilder
.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 {
//写入ResponseBody
response.newBuilder()
.body(exchange.openResponseBody(response))
.build()
}
//收到敞开连贯的Header 敞开IO
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()}")
}
//返回Response
return response
} catch (e: IOException) {
if (sendRequestException != null) {
sendRequestException.addSuppressed(e)
throw sendRequestException
}
throw e
}
}
CallServerInterceptor
的intercept
办法很长,不过逻辑并不简单。大抵流程如下:
- 1、依据Request的配置写入申请行和申请头。
- 2、依据Method判断是否反对申请体,如果反对则尝试写入申请体并发送申请报文,否则间接发送
- 3、读取响应报文,构建Response
- 4、读取响应体,为Response写入ResponseBody
- 5、判断是否要敞开连贯
- 6、返回Response
因为CallServerInterceptor
是最初一个Interceptor
,所以返回的Response
会一级一级的向上传递,最初用户就能拿到包装后的响应Response
了。
BridgeInterceptor
这个拦截器是利用和网络交互的一个桥梁。首先他会获取Request
里的信息,依据申请内容在Request
中增加或者一些申请头,这些都是用户未感知到的。同时这个拦截器还会读取Cookie配置,如果有Cookie信息,也会通过申请头带到服务端。
在Request
信息欠缺后,会调用后续的责任链去解决欠缺的Request
,并期待后续的返回。
val networkResponse = chain.proceed(requestBuilder.build())//期待响应
cookieJar.receiveHeaders(userRequest.url, networkResponse.headers)//解决Cookie
val responseBuilder = networkResponse.newBuilder()
.request(userRequest)//将原始申请信息放入Response
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")
//解决ResponseBody
responseBuilder.body(RealResponseBody(contentType, -1L, gzipSource.buffer()))
}
}
//返回欠缺的Response
return responseBuilder.build()
收到后续的返回后,会对Response
进行解决,并精简一些响应头。最终将欠缺的Response
回传给用户。很多操作都是用户无感知的实现的,深藏功与名。
Response
这就没什么好说的了吧?在通过一些列链式调用和解决,最终用户能够拿到一个Response
对象。在这里用户就能够拿到申请的各种信息以及相应,剩下的就交给用户自行处理了。在用户拿到Response
后,一次网络申请也算实现啦!
总结
话不多说,先上图
再来文字总结一下,OkHttpClinent
类是一个网络申请的配置类,咱们通过构建Request
来形容咱们的申请信息,接着应用newCall
办法能够创立一个RealCall
实例。
RealCall
能够抉择同步执行或者是异步执行,他是咱们与网络交互的一个桥梁。如果是同步申请,则会间接调用gerResponseWithInterceptorChain()
办法创立拦截器责任链。如果是异步申请,则会散发到Dispatcher
,Dispatcher
最终会应用线程池执行这个申请,最终也还是会走到gerResponseWithInterceptorChain()
办法。
在gerResponseWithInterceptorChain()
办法中,会将所有的拦截器依照肯定程序封装进一个列表,构建一个RealInterceptorChain
。proceed
办法会调用各个拦截器的intercept
办法,拦截器在解决实现本人的职责后,持续调用proceed
办法。
RetryAndFollowUpInterceptor
负责处理错误重试和重定向,BridgeInterceptor
负责包装申请和返回数据,CacheInterceptor
负责缓存的解决,而ConnectInterceptor
则真正的关上了连贯,最初通过CallServerInterceptor
进行网络IO,发送和解决报文。
OkHttp
底层采纳了Socket
进行网络连接,采纳OkIO
进行网络IO,有连接池逻辑,会存储RealConnection
实例,缩小过多连贯产生的开销。
浏览源码不难,难的是写源码时候应该具备的思维。通过浏览OkHttp
源码能够让咱们学习到很多设计思维:通过Builder模式
构建简单对象、通过责任链模式
有序的散发工作和回传、性能的形象
等等。好的开源框架的源码浏览真的能让咱们播种很多,咱们应该学以致用,这样就算有一天他人让你做一个相似的性能时候,你也不会毫无脉络。心愿这篇文章能让你有所播种,当然我更倡议你本人浏览一遍源码,兴许会有不一样的播种。
能看到这里也不容易,棘手给个赞吧,欢送分享不同的见解(#^.^#)
视频:
资深架构师带你逐题详解Android大厂精选高频面试题:OkHttp的应用流程;OkHttp散发器原理
OkHttp散发器线程池上;OkHttp散发器线程池下;OkHttp拦截器责任链设计模式
原文: https://juejin.cn/post/6909445385266135048#comment
发表回复