前言
okhttp
是一套处理 http
网络请求的依赖库,由 square
公司设计研发并开源,目前可以在 java
和 kotlin
中使用。
对于 android app
来说,okhttp
现在几乎已经占据了所有的网络请求操作让,我们了解其内部实现原理可以更好地进行功能扩展、封装以及优化。
本文基于okhttp 4.11.0
进行分析
okhttp
的具体使用可以参考官网,这里不做具体的说明,本文主要从okhttp
的使用入手,来具体分析okhttp
的实现原理。
介绍
okhttp是通过socket和okio进行交换数据的
val client = okhttpclient() val request = request.builder().get().url("http://xxx").build() client.newcall(request).enqueue(object : callback { override fun onfailure(call: call, e: ioexception) { } override fun onresponse(call: call, response: response) { } })
从上面我们可以看到几个okhttp
重要的组成部分
- okhttpclient:
okhttp
用于请求的执行客户端 - request: 通过bulider设计模式,构建的一个请求对象
- call: 是通过
client.newcall
生成的请求执行对象,当执行了execute
之后才会真正的开始执行网络请求 - response: 是通过网络请求后,从服务器返回的信息都在里面。内含返回的状态码,以及代表响应消息正文的
responsebody
- interceptor 用户定义的拦截器,在重试拦截器之前执行
- retryandfollowupinterceptor 重试拦截器
- bridgeinterceptor 建立网络桥梁的拦截器,主要是为了给网络请求时候,添加各种各种必要参数。如cookie,content-type
- cacheinterceptor 缓存拦截器,主要是为了在网络请求时候,根据返回码处理缓存。
- connectinterceptor 连接拦截器,主要是为了从连接池子中查找可以复用的socket连接。
- networkinterceptors 用户定义的网络拦截器,在callserverinterceptor(执行网络请求拦截器)之前运行。
- callserverinterceptor 真正执行网络请求的逻辑。
执行流程
okhttpclient
class builder constructor() { //okhttp 请求分发器,是整个okhttpclient的执行核心 internal var dispatcher: dispatcher = dispatcher() //okhttp连接池,不过会把任务委托给realconnectionpool处理 internal var connectionpool: connectionpool = connectionpool() //用户定义的拦截器,在重试拦截器之前执行 internal val interceptors: mutablelist<interceptor> = mutablelistof() //用户定义的网络拦截器,在callserverinterceptor(执行网络请求拦截器)之前运行。 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 //是否重定向到https internal var followsslredirects = true //cookie持久化的设置 internal var cookiejar: cookiejar = cookiejar.no_cookies //缓存设置 internal var cache: cache? = null //dns设置 internal var dns: dns = dns.system //代理设置 internal var proxy: proxy? = null internal var proxyselector: proxyselector? = null internal var proxyauthenticator: authenticator = authenticator.none //默认的socket连接池 internal var socketfactory: socketfactory = socketfactory.getdefault() //用于https的socket连接池 internal var sslsocketfactoryornull: sslsocketfactory? = null //用于信任https证书的对象 internal var x509trustmanagerornull: x509trustmanager? = null internal var connectionspecs: list<connectionspec> = default_connection_specs //http协议集合 internal var protocols: list<protocol> = default_protocols //https对host的检验 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 internal var minwebsocketmessagetocompress = realwebsocket.default_minimum_deflate_size internal var routedatabase: routedatabase? = null }
client.newcall(request):
override fun newcall(request: request): call = realcall(this, request, forwebsocket = false)
在这里生成一个realcall对象,这里第三个参数是否为websocket,默认是false。 在拿到realcall对象之后,这里有两种方式起发送网络请求:
- execute() : 这种方式很少用
- enqueue() : 这种方式是将每个请求放在队列中,按照顺序逐个去进行消费。
realcall.enqueue()
override fun enqueue(responsecallback: callback) { check(executed.compareandset(false, true)) { "already executed" } callstart() client.dispatcher.enqueue(asynccall(responsecallback)) } private fun callstart() { this.callstacktrace = platform.get().getstacktraceforcloseable("response.body().close()") eventlistener.callstart(this) }
这里主要做了一下几步
- 首先回调eventlistener的callstart()方法,
- 然后把创建asynccall对象将responsecallback传进去。
- 最后dispatcher的enqueue()方法.
dispatcher.enqueue()
class dispatcher constructor() { ...... //按运行顺序准备异步调用的队列 private val readyasynccalls = arraydeque<asynccall>() //正在运行的异步请求队列, 包含取消但是还未finish的asynccall private val runningasynccalls = arraydeque<asynccall>() //正在运行的同步请求队列, 包含取消但是还未finish的realcall private val runningsynccalls = arraydeque<realcall>() ...... internal fun enqueue(call: asynccall) { synchronized(this) { readyasynccalls.add(call) if (!call.call.forwebsocket) { val existingcall = findexistingcallwithhost(call.host) if (existingcall != null) call.reusecallsperhostfrom(existingcall) } } promoteandexecute() } private fun findexistingcallwithhost(host: string): asynccall? { for (existingcall in runningasynccalls) { if (existingcall.host == host) return existingcall } for (existingcall in readyasynccalls) { if (existingcall.host == host) return existingcall } return null }
- 首先将asynccall加入readyasynccalls队列中.
- 然后通过findexistingcallwithhost查找在runningasynccalls和readyasynccalls是否存在相同host的asynccall,如果存在则调用call.reusecallsperhostfrom()进行复用
- 最后调用 promoteandexecute() 通过线程池执行队列中的asynccall对象
private fun promoteandexecute(): boolean { this.assertthreaddoesntholdlock() val executablecalls = mutablelistof<asynccall>() //判断是否有请求正在执行 val isrunning: boolean //加锁,保证线程安全 synchronized(this) { //遍历 readyasynccalls 队列 val i = readyasynccalls.iterator() while (i.hasnext()) { val asynccall = i.next() //runningasynccalls的数量不能大于最大并发请求数 64 if (runningasynccalls.size >= this.maxrequests) break // max capacity. //同一host的最大数是5 if (asynccall.callsperhost.get() >= this.maxrequestsperhost) continue // host max capacity. //从readyasynccalls队列中移除并加入到executablecalls和runningasynccalls中 i.remove() asynccall.callsperhost.incrementandget() executablecalls.add(asynccall) runningasynccalls.add(asynccall) } isrunning = runningcallscount() > 0 } //遍历executablecalls 执行asynccall for (i in 0 until executablecalls.size) { val asynccall = executablecalls[i] asynccall.executeon(executorservice) } return isrunning }
在这里遍历readyasynccalls队列,判断runningasynccalls的数量是否大于最大并发请求数64, 判断同一host的请求是否大于5,然后将asynccall从readyasynccalls队列中移除,并加入到executablecalls和runningasynccalls中,遍历executablecalls 执行asynccall.
internal inner class asynccall( private val responsecallback: callback ) : runnable { ...... fun executeon(executorservice: executorservice) { client.dispatcher.assertthreaddoesntholdlock() var success = false try { //执行asynccall 的run方法 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) { client.dispatcher.finished(this) // this call is no longer running! } } } override fun run() { threadname("okhttp ${redactedurl()}") { var signalledcallback = false timeout.enter() try { //执行okhttp的拦截器 获取response对象 val response = getresponsewithinterceptorchain() signalledcallback = true //通过该方法将response对象回调出去 responsecallback.onresponse(this@realcall, response) } catch (e: ioexception) { if (signalledcallback) { platform.get().log("callback failure for ${tologgablestring()}", platform.info, e) } else { //遇到io异常 回调失败方法 responsecallback.onfailure(this@realcall, e) } } catch (t: throwable) { //遇到其他异常 回调失败方法 cancel() if (!signalledcallback) { val canceledexception = ioexception("canceled due to $t") canceledexception.addsuppressed(t) responsecallback.onfailure(this@realcall, canceledexception) } throw t } finally { client.dispatcher.finished(this) } } } }
这里可以看到asynccall就是一个runable对象,线程执行就会调用该对象的run方法,而executeon方法就是执行runable对象. 在run方法中主要执行了以下几步:
- 调用getresponsewithinterceptorchain()执行okhttp拦截器,获取response对象
- 调用responsecallback的onresponse方法将response对象回调出去
- 如果遇见ioexception异常则调用responsecallback的onfailure方法将异常回调出去
- 如果遇到其他异常,调用cancel()方法取消请求,调用responsecallback的onfailure方法将异常回调出去
- 调用dispatcher的finished方法结束执行
@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 //如果不是sockect 添加newtwork拦截器 if (!forwebsocket) { interceptors += client.networkinterceptors } 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 { //执行拦截器责任链获取response 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) } } }
在这里主要执行了以下几步操作
- 首先构建一个可变interceptor集合,将所有拦截器添加进去,这里如果是websocket则不添加networkinterceptor拦截器,这个interceptor集合的添加顺序也就是okhttp拦截器的执行顺序
- 构建一个realinterceptorchain对象,将所有的拦截器包裹
- 调用realinterceptorchain的proceed的方法,获得response对象
简单的总结一下:这里才用了责任链设计模式,构建realinterceptorchain对象,然后执行proceed方法获取response对象
fun interface interceptor { //拦截方法 @throws(ioexception::class) fun intercept(chain: chain): response companion object { inline operator fun invoke(crossinline block: (chain: chain) -> response): interceptor = interceptor { block(it) } } interface chain { //获取request对象 fun request(): request //处理请求获取reponse @throws(ioexception::class) fun proceed(request: request): response ...... } }
class realinterceptorchain( internal val call: realcall, private val interceptors: list<interceptor>, private val index: int, internal val exchange: exchange?, internal val request: request, internal val connecttimeoutmillis: int, internal val readtimeoutmillis: int, internal val writetimeoutmillis: int ) : interceptor.chain { internal fun copy( index: int = this.index, exchange: exchange? = this.exchange, request: request = this.request, connecttimeoutmillis: int = this.connecttimeoutmillis, readtimeoutmillis: int = this.readtimeoutmillis, writetimeoutmillis: int = this.writetimeoutmillis ) = realinterceptorchain(call, interceptors, index, exchange, request, connecttimeoutmillis, readtimeoutmillis, writetimeoutmillis) ...... override fun call(): call = call override fun request(): request = request @throws(ioexception::class) override fun proceed(request: request): response { check(index < interceptors.size) ...... val next = copy(index = index + 1, request = request) val interceptor = interceptors[index] @suppress("useless_elvis") val response = interceptor.intercept(next) ?: throw nullpointerexception( "interceptor $interceptor returned null") ...... return response } }
这里看一看到copy()方法就是创建了一个realinterceptorchain()对象,不过需要注意的是index在创建对象时是index = index + 1,这样就会执行index对应下标的拦截器,不断的调用下一个拦截器,直到有response对象返回,也就是chain.proceed(originalrequest)结束。
interceptor
下面我们来具体分析一下拦截器
retryandfollowupinterceptor
主要处理了如下几个方向的问题:
- 1.异常,或者协议重试(408客户端超时,权限问题,503服务暂时不处理,retry-after为0)
- 2.重定向
- 3.重试的次数不能超过20次。
@throws(ioexception::class) override fun intercept(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) { //这里会新建一个exchangefinder,connectinterceptor会使用到 call.enternetworkinterceptorexchange(request, newexchangefinder) var response: response var closeactiveexchange = true try { if (call.iscanceled()) { throw ioexception("canceled") } try { response = realchain.proceed(request) newexchangefinder = true } catch (e: routeexception) { //尝试通过路由连接失败。该请求将不会被发送。 if (!recover(e.lastconnectexception, call, request, requestsendstarted = false)) { throw e.firstconnectexception.withsuppressed(recoveredfailures) } else { recoveredfailures += e.firstconnectexception } newexchangefinder = false continue } catch (e: ioexception) { //尝试与服务器通信失败。该请求可能已发送。 if (!recover(e, call, request, requestsendstarted = e !is connectionshutdownexception)) { throw e.withsuppressed(recoveredfailures) } else { recoveredfailures += e } newexchangefinder = false continue } //尝试关联上一个response,注意:body是为null if (priorresponse != null) { response = response.newbuilder() .priorresponse(priorresponse.newbuilder() .body(null) .build()) .build() } val exchange = call.interceptorscopedexchange //会根据 responsecode 来判断,构建一个新的request并返回来重试或者重定向 val followup = followuprequest(response, exchange) if (followup == null) { if (exchange != null && exchange.isduplex) { call.timeoutearlyexit() } closeactiveexchange = false return response } //如果请求体是一次性的,不需要再次重试 val followupbody = followup.body if (followupbody != null && followupbody.isoneshot()) { closeactiveexchange = false return response } response.body?.closequietly() //最大重试次数,不同的浏览器是不同的,比如:chrome为21,safari则是16 if (++followupcount > max_follow_ups) { throw protocolexception("too many follow-up requests: $followupcount") } request = followup priorresponse = response } finally { call.exitnetworkinterceptorexchange(closeactiveexchange) } } }
- 1.调用realcall的enternetworkinterceptorexchange方法实例化一个
exchangefinder
在realcall对象中。 - 2.执行realcall的proceed 方法,进入下一个拦截器,进行下一步的请求处理。
- 3.如果出现路由异常,则通过recover方法校验,当前的连接是否可以重试,不能重试则抛出异常,离开当前的循环。
private fun recover( e: ioexception, call: realcall, userrequest: request, requestsendstarted: boolean ): boolean { //禁止重连 if (!client.retryonconnectionfailure) return false // 不能再次发送请求体 if (requestsendstarted && requestisoneshot(e, userrequest)) return false // 致命异常 if (!isrecoverable(e, requestsendstarted)) return false // 没有更多线路可以重连 if (!call.retryafterfailure()) return false // 对于故障恢复,将相同的路由选择器与新连接一起使用 return true }
bridgeinterceptor
主要处理了如下几个问题:
- 主要将content-type、content-length、host等一些数据添加到头部。
- 拿到数据之后对数据进行处理,判断是否为gzip,进行对数据数据解压。
@throws(ioexception::class) 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()) } 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()) } 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") } val cookies = cookiejar.loadforrequest(userrequest.url) if (cookies.isnotempty()) { requestbuilder.header("cookie", cookieheader(cookies)) } if (userrequest.header("user-agent") == null) { requestbuilder.header("user-agent", useragent) } //执行下一个拦截器 val networkresponse = chain.proceed(requestbuilder.build()) cookiejar.receiveheaders(userrequest.url, networkresponse.headers) //创建一个新的responsebuilder,目的是将原始请求数据构建到response中 val responsebuilder = networkresponse.newbuilder() .request(userrequest) 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() //修改response header信息,移除content-encoding,content-length信息 responsebuilder.headers(strippedheaders) val contenttype = networkresponse.header("content-type" //修改response body信息 responsebuilder.body(realresponsebody(contenttype, -1l, gzipsource.buffer())) } } return responsebuilder.build() }
- 设置头部的content-type.说明内容类型是什么
- 如果contentlength大于等于0,则设置头部的content-length(说明内容大小是多少);否则设置头部的transfer-encoding为chunked(说明传输编码为分块传输)
- 如果host不存在,设置头部的host(在http 1.1之后出现,可以通过同一个url访问到不同主机,从而实现服务器虚拟服务器的负载均衡。如果1.1之后不设置就会返回404)。
- 如果connection不存在,设置头部的connection为keep-alive(代表连接状态需要保持活跃)
- 如果accept-encoding且range为空,则强制设置accept-encoding为gzip(说明请求将会以gzip方式压缩)
- 从cookiejar的缓存中取出cookie设置到头部的cookie
- 如果user-agent为空,则设置user-agent到头部
cacheinterceptor
用户通过okhttpclient.cache
来配置缓存,缓存拦截器通过cachestrategy
来判断是使用网络还是缓存来构建response
。
@throws(ioexception::class) override fun intercept(chain: interceptor.chain): response { val call = chain.call() //通过request从okhttpclient.cache中获取缓存 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) val listener = (call as? realcall)?.eventlistener ?: eventlistener.none //有缓存但不适用,关闭它 if (cachecandidate != null && cacheresponse == null) { cachecandidate.body?.closequietly() } //如果网络被禁止,但是缓存又是空的,构建一个code为504的response,并返回 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().also { listener.satisfactionfailure(call, it) } } //如果我们禁用了网络不使用网络,且有缓存,直接根据缓存内容构建并返回response if (networkrequest == null) { return cacheresponse!!.newbuilder() .cacheresponse(stripbody(cacheresponse)) .build().also { listener.cachehit(call, it) } } //为缓存添加监听 if (cacheresponse != null) { listener.cacheconditionalhit(call, cacheresponse) } else if (cache != null) { listener.cachemiss(call) } var networkresponse: response? = null try { //执行下一个拦截器 networkresponse = chain.proceed(networkrequest) } finally { //捕获i/o或其他异常,请求失败,networkresponse为空,且有缓存的时候,不暴露缓存内容 if (networkresponse == null && cachecandidate != null) { //否则关闭缓存响应体 cachecandidate.body?.closequietly() } } //如果有缓存 if (cacheresponse != null) { //且网络返回response code为304的时候,使用缓存内容新构建一个response返回。 if (networkresponse?.code == http_not_modified) { 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.also { listener.cachehit(call, it) } } else { //否则关闭缓存响应体 cacheresponse.body?.closequietly() } } //构建网络请求的response val response = networkresponse!!.newbuilder() .cacheresponse(stripbody(cacheresponse)) .networkresponse(stripbody(networkresponse)) .build() //如果cache不为null,即用户在okhttpclient中配置了缓存,则将上一步新构建的网络请求response存到cache中 if (cache != null) { //根据response的code,header以及cachecontrol.nostore来判断是否可以缓存 if (response.promisesbody() && cachestrategy.iscacheable(response, networkrequest)) { // 将该response存入缓存 val cacherequest = cache.put(response) return cachewritingresponse(cacherequest, response).also { if (cacheresponse != null) { listener.cachemiss(call) } } } //根据请求方法来判断缓存是否有效,只对get请求进行缓存,其它方法的请求则移除 if (httpmethod.invalidatescache(networkrequest.method)) { try { //缓存无效,将该请求缓存从client缓存配置中移除 cache.remove(networkrequest) } catch (_: ioexception) { } } } return response }
网络请求前:
- 首先根据request从okhttpclient.cache中获取缓存,通过
cachestrategy
获取本次请求的请求体及缓存的响应体。 - 如果 请求体
networkrequest
和响应体cacheresponse
都为空的话,则返回错误码为 504 - 如果 请求体
networkrequest
为空 响应体cacheresponse
不为空的话,则将该响应体返回 - 如果请求体
networkrequest
不为空的话,则进入下一个拦截器。
网络请求后:
- 如果当前
cacheresponse
不为空,且networkresponse
状态码为304, 则代表数据没有变化,那么就会根据cacheresponse
构建一个新的response
,根据当前时间更新到缓存当中,并返回到上一拦截器中 - 如果
networkresponse
状态码不为304,则判断是否进行缓存,最后返回到上一拦截器中
从lrucache中获取缓存
val cachecandidate = cache?.get(chain.request())
internal fun get(request: request): response? { val key = key(request.url) val snapshot: disklrucache.snapshot = try { cache[key] ?: return null } catch (_: ioexception) { return null // give up because the cache cannot be read. } val entry: entry = try { entry(snapshot.getsource(entry_metadata)) } catch (_: ioexception) { snapshot.closequietly() return null } val response = entry.response(snapshot) if (!entry.matches(request, response)) { response.body?.closequietly() return null } return response }
@jvmstatic fun key(url: httpurl): string = url.tostring().encodeutf8().md5().hex()
- 首先将url转化为urf-8,并且通过md5拿到摘要,再调用hex获取16进制的字符串,该字符串就是lrucache的key;
- 通过key获取到
disklrucache.snapshot
对象(这里在disklrucache
中重写了get方法),根据disklrucache.snapshot
对象获取到okio 的source。
disklrucache:
@synchronized @throws(ioexception::class) operator fun get(key: string): snapshot? { initialize() checknotclosed() validatekey(key) val entry = lruentries[key] ?: return null val snapshot = entry.snapshot() ?: return null redundantopcount++ journalwriter!!.writeutf8(read) .writebyte(' '.toint()) .writeutf8(key) .writebyte('\n'.toint()) if (journalrebuildrequired()) { cleanupqueue.schedule(cleanuptask) } return snapshot }
- 最后将数据转化为响应体
再来看看那些响应体需要缓存:
这里是网络请求回来,判断是否需要缓存的处理
if (cache != null) { if (response.promisesbody() && cachestrategy.iscacheable(response, networkrequest)) { val cacherequest = cache.put(response) return cachewritingresponse(cacherequest, response).also { if (cacheresponse != null) { listener.cachemiss(call) } } } if (httpmethod.invalidatescache(networkrequest.method)) { try { cache.remove(networkrequest) } catch (_: ioexception) { } } }
- 首先根据cache对象是否为空,决定是否进入缓存判断
response.promisesbody()
判断响应体是否有正文,cachestrategy.iscacheable(response, networkrequest)
这里是判断哪些状态码需要缓存- 这里
httpmethod.invalidatescache(networkrequest.method)
判断哪些请求方式是否为post
、patch
、put
、delete
、move
,如果为true的话则移除缓存。
fun iscacheable(response: response, request: request): boolean { when (response.code) { http_ok, http_not_authoritative, http_no_content, http_mult_choice, http_moved_perm, http_not_found, http_bad_method, http_gone, http_req_too_long, http_not_implemented, statusline.http_perm_redirect -> { } http_moved_temp, statusline.http_temp_redirect -> { if (response.header("expires") == null && response.cachecontrol.maxageseconds == -1 && !response.cachecontrol.ispublic && !response.cachecontrol.isprivate) { return false } } else -> { return false } } return !response.cachecontrol.nostore && !request.cachecontrol.nostore }
如果状态码为200
、203
、204
、301
、404
、405
、410
、414
、501
、308
都可以缓存,其他则返回false
不进行缓存
以上就是android开发okhttp执行流程源码分析的详细内容,更多关于android okhttp执行流程的资料请关注www.887551.com其它相关文章!