当前位置: 首页 > news >正文

响应式网站设计的规范全球网站排名前十

响应式网站设计的规范,全球网站排名前十,核心关键词举例,福田公司在哪里序、慢慢来才是最快的方法。 背景 OkHttp 是一套处理 HTTP 网络请求的依赖库#xff0c;由 Square 公司设计研发并开源#xff0c;目前可以在 Java 和 Kotlin 中使用。对于 Android App 来说#xff0c;OkHttp 现在几乎已经占据了所有的网络请求操作。 OKHttp源码官网 版…序、慢慢来才是最快的方法。 背景 OkHttp 是一套处理 HTTP 网络请求的依赖库由 Square 公司设计研发并开源目前可以在 Java 和 Kotlin 中使用。对于 Android App 来说OkHttp 现在几乎已经占据了所有的网络请求操作。 OKHttp源码官网   版本 api com.squareup.okhttp3:okhttp:4.10.0发起网络请求示例代码 val okHttpClient OkHttpClient()val request :Request Request.Builder().url().build()val newCall okHttpClient.newCall(request)//同步请求newCall.execute()//异步请求newCall.enqueue(object : Callback {override fun onFailure(call: Call, e: IOException) {TODO(Not yet implemented)}override fun onResponse(call: Call, response: Response) {TODO(Not yet implemented)}})核心类 OkHttpClient 、Request 、Call 、RealCall 、Dispatcher 、Deque 、AsyncCall 、Response   OkHttpClient: Okhttp用于请求的执行客户端Request: 通过Bulider设计模式构建的一个请求对象Call: 是通过 client.newCall 生成的请求执行对象当执行了execute之后才会真正的开始执行网络请求Response: 是通过网络请求后从服务器返回的信息都在里面。内含返回的状态码以及代表响应消息正文的ResponseBody interceptor 用户定义的拦截器在重试拦截器之前执行retryAndFollowUpInterceptor 重试拦截器BridgeInterceptor 建立网络桥梁的拦截器主要是为了给网络请求时候添加各种各种必要参数。如CookieContent-typeCacheInterceptor 缓存拦截器主要是为了在网络请求时候根据返回码处理缓存。ConnectInterceptor 连接拦截器主要是为了从连接池子中查找可以复用的socket连接。networkInterceptors 用户定义的网络拦截器在CallServerInterceptor(执行网络请求拦截器)之前运行。CallServerInterceptor 真正执行网络请求的逻辑。 1.网路请求流程 OkHttpClient 网络配置层 class Builder constructor() {//Okhttp 请求分发器是整个OkhttpClient的执行核心internal var dispatcher: Dispatcher Dispatcher()//Okhttp连接池不过会把任务委托给RealConnectionPool处理internal var connectionPool: ConnectionPool ConnectionPool()//用户定义的拦截器在重试拦截器之前执行internal val interceptors: MutableListInterceptor mutableListOf()//用户定义的网络拦截器在CallServerInterceptor(执行网络请求拦截器)之前运行。internal val networkInterceptors: MutableListInterceptor mutableListOf()//流程监听器internal var eventListenerFactory: EventListener.Factory EventListener.NONE.asFactory()//连接失败时是否重连internal var retryOnConnectionFailure true//服务器认证设置internal var authenticator: Authenticator Authenticator.NONE//是否重定向internal var followRedirects true//是否重定向到httpsinternal 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? nullinternal var proxySelector: ProxySelector? nullinternal var proxyAuthenticator: Authenticator Authenticator.NONE//默认的socket连接池internal var socketFactory: SocketFactory SocketFactory.getDefault()//用于https的socket连接池internal var sslSocketFactoryOrNull: SSLSocketFactory? null//用于信任Https证书的对象internal var x509TrustManagerOrNull: X509TrustManager? nullinternal var connectionSpecs: ListConnectionSpec DEFAULT_CONNECTION_SPECS//http协议集合internal var protocols: ListProtocol DEFAULT_PROTOCOLS//https对host的检验internal var hostnameVerifier: HostnameVerifier OkHostnameVerifierinternal var certificatePinner: CertificatePinner CertificatePinner.DEFAULTinternal var certificateChainCleaner: CertificateChainCleaner? null//请求超时internal var callTimeout 0//连接超时internal var connectTimeout 10_000//读取超时internal var readTimeout 10_000//写入超时internal var writeTimeout 10_000internal var pingInterval 0internal var minWebSocketMessageToCompress RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZEinternal 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 ArrayDequeAsyncCall()//正在运行的异步请求队列, 包含取消但是还未finish的AsyncCall private val runningAsyncCalls ArrayDequeAsyncCall()//正在运行的同步请求队列, 包含取消但是还未finish的RealCall private val runningSyncCalls ArrayDequeRealCall()......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对象 Dispatcher.promoteAndExecute() private fun promoteAndExecute(): Boolean {this.assertThreadDoesntHoldLock()val executableCalls mutableListOfAsyncCall()//判断是否有请求正在执行val isRunning: Boolean//加锁保证线程安全synchronized(this) {//遍历 readyAsyncCalls 队列val i readyAsyncCalls.iterator()while (i.hasNext()) {val asyncCall i.next()//runningAsyncCalls的数量不能大于最大并发请求数 64if (runningAsyncCalls.size this.maxRequests) break // Max capacity.//同一Host的最大数是5if (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 执行asyncCallfor (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. RealCall.AsyncCall.exceuteOn() internal inner class AsyncCall(private val responseCallback: Callback ) : Runnable {......fun executeOn(executorService: ExecutorService) {client.dispatcher.assertThreadDoesntHoldLock()var success falsetry {//执行AsyncCall 的run方法executorService.execute(this)success true} catch (e: RejectedExecutionException) {val ioException InterruptedIOException(executor rejected)ioException.initCause(e)noMoreExchanges(ioException)responseCallback.onFailure(thisRealCall, ioException)} finally {if (!success) {client.dispatcher.finished(this) // This call is no longer running!}}}override fun run() {threadName(OkHttp ${redactedUrl()}) {var signalledCallback falsetimeout.enter()try {//执行OkHttp的拦截器 获取response对象val response getResponseWithInterceptorChain()signalledCallback true//通过该方法将response对象回调出去responseCallback.onResponse(thisRealCall, response)} catch (e: IOException) {if (signalledCallback) {Platform.get().log(Callback failure for ${toLoggableString()}, Platform.INFO, e)} else {//遇到IO异常 回调失败方法responseCallback.onFailure(thisRealCall, e)}} catch (t: Throwable) {//遇到其他异常 回调失败方法cancel()if (!signalledCallback) {val canceledException IOException(canceled due to $t)canceledException.addSuppressed(t)responseCallback.onFailure(thisRealCall, 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方法结束执行 RealCall.getResponseWithInterceptorChain() Throws(IOException::class) internal fun getResponseWithInterceptorChain(): Response {// 拦截器集合val interceptors mutableListOfInterceptor()//添加用户自定义集合interceptors client.interceptorsinterceptors 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 falsetry {//执行拦截器责任链获取Responseval response chain.proceed(originalRequest)//如果取消了 则抛出异常if (isCanceled()) {response.closeQuietly()throw IOException(Canceled)}return response} catch (e: IOException) {calledNoMoreExchanges truethrow noMoreExchanges(e) as Throwable} finally {if (!calledNoMoreExchanges) {noMoreExchanges(null)}} }在这里主要执行了以下几步操作 首先构建一个可变interceptor集合将所有拦截器添加进去这里如果是websocket则不添加networkInterceptor拦截器,这个interceptor集合的添加顺序也就是OkHttp拦截器的执行顺序构建一个RealInterceptorChain对象,将所有的拦截器包裹调用RealInterceptorChain的proceed的方法获得Response对象 简单的总结一下这里才用了责任链设计模式构建RealInterceptorChain对象然后执行proceed方法获取response对象 2.Interceptor fun interface Interceptor {//拦截方法Throws(IOException::class)fun intercept(chain: Chain): Responsecompanion object {inline operator fun invoke(crossinline block: (chain: Chain) - Response): Interceptor Interceptor { block(it) }}interface Chain {//获取Request对象fun request(): Request//处理请求获取ReponseThrows(IOException::class)fun proceed(request: Request): Response......} }class RealInterceptorChain(internal val call: RealCall,private val interceptors: ListInterceptor,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 calloverride fun request(): Request requestThrows(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)结束。 RetryAndFollowUpInterceptor(错误重定向拦截器) 主要处理了如下几个方向的问题 1.异常或者协议重试(408客户端超时权限问题503服务暂时不处理retry-after为0)2.重定向3.重试的次数不能超过20次。 RetryAndFollowUpInterceptor.intercept() 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 listOfIOException() while (true) {//这里会新建一个ExchangeFinderConnectInterceptor会使用到call.enterNetworkInterceptorExchange(request, newExchangeFinder)var response: Responsevar closeActiveExchange truetry {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 falsecontinue} catch (e: IOException) {//尝试与服务器通信失败。该请求可能已发送。if (!recover(e, call, request, requestSendStarted e !is ConnectionShutdownException)) {throw e.withSuppressed(recoveredFailures)} else {recoveredFailures e}newExchangeFinder falsecontinue}//尝试关联上一个response注意body是为nullif (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 falsereturn response}//如果请求体是一次性的不需要再次重试val followUpBody followUp.bodyif (followUpBody ! null followUpBody.isOneShot()) {closeActiveExchange falsereturn response}response.body?.closeQuietly()//最大重试次数不同的浏览器是不同的比如Chrome为21Safari则是16if (followUpCount MAX_FOLLOW_UPS) {throw ProtocolException(Too many follow-up requests: $followUpCount)}request followUppriorResponse 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进行对数据数据解压。 BridgeInterceptor.intercept() Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response {//获取原始请求数据val userRequest chain.request()val requestBuilder userRequest.newBuilder()//重新构建请求 添加一些必要的请求头信息val body userRequest.bodyif (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 falseif (userRequest.header(Accept-Encoding) null userRequest.header(Range) null) {transparentGzip truerequestBuilder.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.bodyif (responseBody ! null) {val gzipSource GzipSource(responseBody.source())val strippedHeaders networkResponse.headers.newBuilder().removeAll(Content-Encoding).removeAll(Content-Length).build()//修改response header信息移除Content-EncodingContent-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。 CacheInterceptor.intercept() 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)}}//如果我们禁用了网络不使用网络且有缓存直接根据缓存内容构建并返回responseif (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? nulltry {//执行下一个拦截器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()}}//构建网络请求的responseval 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 nullval snapshot entry.snapshot() ?: return nullredundantOpCountjournalWriter!!.writeUtf8(READ).writeByte( .toInt()).writeUtf8(key).writeByte(\n.toInt())if (journalRebuildRequired()) {cleanupQueue.schedule(cleanupTask)}return snapshot }ConnectInterceptot(链接拦截器) object ConnectInterceptor : Interceptor {Throws(IOException::class)override fun intercept(chain: Interceptor.Chain): Response {val realChain chain as RealInterceptorChainval exchange realChain.call.initExchange(chain)val connectedChain realChain.copy(exchange exchange)return connectedChain.proceed(realChain.request)} }首先初始化一个可交换连接的对象拷贝一个全新的RealInterceptorChain对象并且调用该对象的proceed方法执行下一拦截器 这个拦截器主要操作都在initExchange(chain)当中 initExchange() internal fun initExchange(chain: RealInterceptorChain): Exchange {synchronized(this) {check(expectMoreExchanges) { released }check(!responseBodyOpen)check(!requestBodyOpen)}val exchangeFinder this.exchangeFinder!!val codec exchangeFinder.find(client, chain)val result Exchange(this, eventListener, exchangeFinder, codec)this.interceptorScopedExchange resultthis.exchange resultsynchronized(this) {this.requestBodyOpen truethis.responseBodyOpen true}if (canceled) throw IOException(Canceled)return result }exchangeFinder 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)} }通过findHealthyConnection找到一个健康的连接resultConnection也就是一个活跃的连接调用 resultConnection.newCodec(client, chain)获取到ExchangeCodec进行返回 findHealthyConnection Throws(IOException::class) private fun findHealthyConnection(connectTimeout: Int,readTimeout: Int,writeTimeout: Int,pingIntervalMillis: Int,connectionRetryEnabled: Boolean,doExtensiveHealthChecks: Boolean ): RealConnection {while (true) {val candidate findConnection(connectTimeout connectTimeout,readTimeout readTimeout,writeTimeout writeTimeout,pingIntervalMillis pingIntervalMillis,connectionRetryEnabled connectionRetryEnabled)if (candidate.isHealthy(doExtensiveHealthChecks)) {return candidate}candidate.noNewExchanges()if (nextRouteToTry ! null) continueval routesLeft routeSelection?.hasNext() ?: trueif (routesLeft) continueval routesSelectionLeft routeSelector?.hasNext() ?: trueif (routesSelectionLeft) continuethrow IOException(exhausted all routes)} }findConnection从OkHttp的连接池中找到对应的RealConnection进行返回如果没有的话则创建一个candidate.isHealthy(doExtensiveHealthChecks)检查该连接是否活跃可用如果当前连接是不健康则调用candidate.noNewExchanges()将noNewExchanges设置为true表示该连接存在问题if (routesSelectionLeft) continue判断是否还有其他路由需要尝试如果有的话则返回true进入下一循环。 findConnection() Throws(IOException::class) private fun findConnection(connectTimeout: Int,readTimeout: Int,writeTimeout: Int,pingIntervalMillis: Int,connectionRetryEnabled: Boolean ): RealConnection {if (call.isCanceled()) throw IOException(Canceled)val callConnection call.connection if (callConnection ! null) {var toClose: Socket? nullsynchronized(callConnection) {if (callConnection.noNewExchanges || !sameHostAndPort(callConnection.route().address.url)) {toClose call.releaseConnectionNoEvents()}}if (call.connection ! null) {check(toClose null)return callConnection}toClose?.closeQuietly()eventListener.connectionReleased(call, callConnection)}refusedStreamCount 0connectionShutdownCount 0otherFailureCount 0if (connectionPool.callAcquirePooledConnection(address, call, null, false)) {val result call.connection!!eventListener.connectionAcquired(call, result)return result}val routes: ListRoute?val route: Routeif (nextRouteToTry ! null) {routes nullroute nextRouteToTry!!nextRouteToTry null} else if (routeSelection ! null routeSelection!!.hasNext()) {routes nullroute routeSelection!!.next()} else {var localRouteSelector routeSelectorif (localRouteSelector null) {localRouteSelector RouteSelector(address, call.client.routeDatabase, call, eventListener)this.routeSelector localRouteSelector}val localRouteSelection localRouteSelector.next()routeSelection localRouteSelectionroutes localRouteSelection.routesif (call.isCanceled()) throw IOException(Canceled)if (connectionPool.callAcquirePooledConnection(address, call, routes, false)) {val result call.connection!!eventListener.connectionAcquired(call, result)return result}route localRouteSelection.next()}val newConnection RealConnection(connectionPool, route)call.connectionToCancel newConnectiontry {newConnection.connect(connectTimeout,readTimeout,writeTimeout,pingIntervalMillis,connectionRetryEnabled,call,eventListener)} finally {call.connectionToCancel null}call.client.routeDatabase.connected(newConnection.route())if (connectionPool.callAcquirePooledConnection(address, call, routes, true)) {val result call.connection!!nextRouteToTry routenewConnection.socket().closeQuietly()eventListener.connectionAcquired(call, result)return result}synchronized(newConnection) {connectionPool.put(newConnection)call.acquireConnectionNoEvents(newConnection)}eventListener.connectionAcquired(call, newConnection)return newConnection }call.connection首先从RealCall对象中获取 RealConnection。 在获取到RealConnection对象时存在三种情况 RealConnection对象不为空但是host和port不匹配RealConnection对象不为空完全匹配RealConnection对象为空 判断RealConnection对象是否为空, 如果不为空则检查一下host和port是否匹配。 如果不匹配则调用releaseConnectionNoEvents()把RealConnection绑定的RealCall队列中对应的RealCall移除并从ConnectionPool中移除该RealConnection当前RealCall中绑定的RealConnection设置为空 并获取当前缓存RealConnection的socket对象并关闭该socket。如果noNewExchanges为false并且host和port匹配则返回该callConnection对象如果RealConnection对象为空则会通过connectionPool和route生成一个新的RealConnection对象 我们继续向下看 if (connectionPool.callAcquirePooledConnection(address, call, null, false)) {val result call.connection!!eventListener.connectionAcquired(call, result)return result }callAcquirePooledConnection fun callAcquirePooledConnection(address: Address,call: RealCall,routes: ListRoute?,requireMultiplexed: Boolean ): Boolean {for (connection in connections) {synchronized(connection) {if (requireMultiplexed !connection.isMultiplexed) returnsynchronizedif (!connection.isEligible(address, routes)) returnsynchronizedcall.acquireConnectionNoEvents(connection)return true}}return false }这里我们主要看connection.isEligible是否符合条件 internal fun isEligible(address: Address, routes: ListRoute?): Boolean {assertThreadHoldsLock()//如果当前RealConnection复用的RealCall队列的大小大于allocationLimit 限制大小或者noNewExchanges 为trueif (calls.size allocationLimit || noNewExchanges) return false//如果RealConnection 中的route和当前传递进来的地址的address不一致直接返回false即可if (!this.route.address.equalsNonHost(address)) return false //如果RealConnection 中的route 和传递进来的host一致了那么说明address和host都一致就是一个资源路径可以返回true。if (address.url.host this.route().address.url.host) {return true }// 如果host 不一致且http2Connection 为空也就不是http 2.0协议那么就不可能做到不同的资源路径进行复用的情况直接返回if (http2Connection null) return false //此时就是必须要符合http 2.0的协议才能进行连接的复用也就是路由可以共享。如果传进来的routes是空 或者通过routeMatchesAny 查找只要出现socket的地址一致且是直接连接的地址则返回true返回false一半就是代理的服务。此时就会直接返回if (routes null || !routeMatchesAny(routes)) return false //想要进一步匹配那么整个网络请求的HostnameVerifier 校验服务器主机名的必须为OkHostnameVerifierif (address.hostnameVerifier ! OkHostnameVerifier) return false//其次匹配HttpUrl和RealConnection的route 能否匹配。如果port 端口不匹配则直接返回false如果host 匹配则直接返回true。否则就必须要保证noCoalescedConnections 为true noCoalescedConnections 这个标志位为true则说明该连接可以共享连接但是不共享主机.handshake不为空说明已经经过了三次握手且本次校验可以通过主机服务器名的校验。if (!supportsUrl(address.url)) return falsetry {address.certificatePinner!!.check(address.url.host, handshake()!!.peerCertificates)} catch (_: SSLPeerUnverifiedException) {return false}return true }RouteSelector 生成 var localRouteSelector routeSelector if (localRouteSelector null) {localRouteSelector RouteSelector(address, call.client.routeDatabase, call, eventListener)this.routeSelector localRouteSelector }class RouteSelector(private val address: Address,private val routeDatabase: RouteDatabase,private val call: Call,private val eventListener: EventListener ) {......init {resetNextProxy(address.url, address.proxy)}...... }private fun resetNextProxy(url: HttpUrl, proxy: Proxy?) {fun selectProxies(): ListProxy {if (proxy ! null) return listOf(proxy)val uri url.toUri()if (uri.host null) return immutableListOf(Proxy.NO_PROXY)val proxiesOrNull address.proxySelector.select(uri)if (proxiesOrNull.isNullOrEmpty()) return immutableListOf(Proxy.NO_PROXY)return proxiesOrNull.toImmutableList()}eventListener.proxySelectStart(call, url)proxies selectProxies()nextProxyIndex 0eventListener.proxySelectEnd(call, url, proxies) }如果proxy不为空则创建一个含有proxy的集合返回如果host为空则创建一个Proxy.NO_PROXY的集合返回否则调用address 的proxySelector 的select方法获取代理集合返回 如果有需要进行代理可以在OkhttpClientBuilder的addProxy中为不同的uri设置自己的代理规则。 接着往下看这里是获取route下面创建RealConnection对象需要使用 val localRouteSelection localRouteSelector.next() routeSelection localRouteSelection routes localRouteSelection.routesif (call.isCanceled()) throw IOException(Canceled) ...... route localRouteSelection.next()val newConnection RealConnection(connectionPool, route) 首先调用next获取 Selection对象通过调用next方法获取route生成RealConnection对象。下面逐步分析。 Throws(IOException::class) operator fun next(): Selection {if (!hasNext()) throw NoSuchElementException()val routes mutableListOfRoute()while (hasNextProxy()) {val proxy nextProxy()for (inetSocketAddress in inetSocketAddresses) {val route Route(address, proxy, inetSocketAddress)if (routeDatabase.shouldPostpone(route)) {postponedRoutes route} else {routes route}}if (routes.isNotEmpty()) {break}}if (routes.isEmpty()) {routes postponedRoutespostponedRoutes.clear()}return Selection(routes) }Throws(IOException::class) private fun nextProxy(): Proxy {if (!hasNextProxy()) {throw SocketException(No route to ${address.url.host}; exhausted proxy configurations:$proxies)}val result proxies[nextProxyIndex]resetNextInetSocketAddress(result)return result }nextProxy不断的遍历获取所有的proxy调用resetNextInetSocketAddress创建route添加到集合当中 Throws(IOException::class) private fun resetNextInetSocketAddress(proxy: Proxy) {// Clear the addresses. Necessary if getAllByName() below throws!val mutableInetSocketAddresses mutableListOfInetSocketAddress()inetSocketAddresses mutableInetSocketAddressesval socketHost: Stringval socketPort: Intif (proxy.type() Proxy.Type.DIRECT || proxy.type() Proxy.Type.SOCKS) {socketHost address.url.hostsocketPort address.url.port} else {val proxyAddress proxy.address()require(proxyAddress is InetSocketAddress) {Proxy.address() is not an InetSocketAddress: ${proxyAddress.javaClass}}socketHost proxyAddress.socketHostsocketPort proxyAddress.port}if (socketPort !in 1..65535) {throw SocketException(No route to $socketHost:$socketPort; port is out of range)}if (proxy.type() Proxy.Type.SOCKS) {mutableInetSocketAddresses InetSocketAddress.createUnresolved(socketHost, socketPort)} else {eventListener.dnsStart(call, socketHost)// Try each address for best behavior in mixed IPv4/IPv6 environments.val addresses address.dns.lookup(socketHost)if (addresses.isEmpty()) {throw UnknownHostException(${address.dns} returned no addresses for $socketHost)}eventListener.dnsEnd(call, socketHost, addresses)for (inetAddress in addresses) {mutableInetSocketAddresses InetSocketAddress(inetAddress, socketPort)}} }如果代理类型是Proxy.Type.SOCKS则先获取address.url的host和port并调用InetSocketAddress.createUnresolved解析并添加到mutableInetSocketAddresses集合中。如果代理类型是Proxy.Type.DIRECT则先获取address.url的host和port然后调用address.dns的lookup方法获取地址并通过改地址和port生成InetSocketAddress添加到mutableInetSocketAddresses集合中。如果代理类型是Proxy.Type.HTTP,则获取传递进来的Proxy中的host和port,调用address.dns的lookup方法获取地址并通过改地址和port生成InetSocketAddress添加到mutableInetSocketAddresses集合中。 newConnection.connect() fun connect(connectTimeout: Int,readTimeout: Int,writeTimeout: Int,pingIntervalMillis: Int,connectionRetryEnabled: Boolean,call: Call,eventListener: EventListener ) {check(protocol null) { already connected }var routeException: RouteException? nullval connectionSpecs route.address.connectionSpecsval connectionSpecSelector ConnectionSpecSelector(connectionSpecs)if (route.address.sslSocketFactory null) {if (ConnectionSpec.CLEARTEXT !in connectionSpecs) {throw RouteException(UnknownServiceException(CLEARTEXT communication not enabled for client))}val host route.address.url.hostif (!Platform.get().isCleartextTrafficPermitted(host)) {throw RouteException(UnknownServiceException(CLEARTEXT communication to $host not permitted by network security policy))}} else {if (Protocol.H2_PRIOR_KNOWLEDGE in route.address.protocols) {throw RouteException(UnknownServiceException(H2_PRIOR_KNOWLEDGE cannot be used with HTTPS))}}while (true) {try {if (route.requiresTunnel()) {connectTunnel(connectTimeout, readTimeout, writeTimeout, call, eventListener)if (rawSocket null) {break}} else {connectSocket(connectTimeout, readTimeout, call, eventListener)}establishProtocol(connectionSpecSelector, pingIntervalMillis, call, eventListener)eventListener.connectEnd(call, route.socketAddress, route.proxy, protocol)break} catch (e: IOException) {socket?.closeQuietly()rawSocket?.closeQuietly()socket nullrawSocket nullsource nullsink nullhandshake nullprotocol nullhttp2Connection nullallocationLimit 1eventListener.connectFailed(call, route.socketAddress, route.proxy, null, e)if (routeException null) {routeException RouteException(e)} else {routeException.addConnectException(e)}if (!connectionRetryEnabled || !connectionSpecSelector.connectionFailed(e)) {throw routeException}}}if (route.requiresTunnel() rawSocket null) {throw RouteException(ProtocolException(Too many tunnel connections attempted: $MAX_TUNNEL_ATTEMPTS))}idleAtNs System.nanoTime() }这里分为两种情况 requiresTunnel判断sslSocketFactory不为空并且代理模式为Proxy.Type.HTTP时会调用connectTunnel连接socket其实最终还是调用 connectSocket方法。requiresTunnel为false时则直接调用connectSocket连接socket 完成上面的操作之后调用establishProtocol方法 Throws(IOException::class) private fun connectSocket(connectTimeout: Int,readTimeout: Int,call: Call,eventListener: EventListener ) {val proxy route.proxyval address route.addressval rawSocket when (proxy.type()) {Proxy.Type.DIRECT, Proxy.Type.HTTP - address.socketFactory.createSocket()!!else - Socket(proxy)}this.rawSocket rawSocketeventListener.connectStart(call, route.socketAddress, proxy)rawSocket.soTimeout readTimeouttry {Platform.get().connectSocket(rawSocket, route.socketAddress, connectTimeout)} catch (e: ConnectException) {throw ConnectException(Failed to connect to ${route.socketAddress}).apply {initCause(e)}}try {source rawSocket.source().buffer()sink rawSocket.sink().buffer()} catch (npe: NullPointerException) {if (npe.message NPE_THROW_WITH_NULL) {throw IOException(npe)}} }如果代理模式是Proxy.Type.DIRECT, Proxy.Type.HTTP则通过SocketFactory创建socket对象。如果代理模式是Proxy.Type.SOCKS则直接new 一个socekt对象。通过connectSocket方法调用socekt的connect方法建立连接。通过Okio分别获取source 写入流和sink 输出流缓存在RealConnection中。 connectTunnel Throws(IOException::class) private fun connectTunnel(connectTimeout: Int,readTimeout: Int,writeTimeout: Int,call: Call,eventListener: EventListener ) {var tunnelRequest: Request createTunnelRequest()val url tunnelRequest.urlfor (i in 0 until MAX_TUNNEL_ATTEMPTS) {//MAX_TUNNEL_ATTEMPTS21connectSocket(connectTimeout, readTimeout, call, eventListener)tunnelRequest createTunnel(readTimeout, writeTimeout, tunnelRequest, url) ?: break rawSocket?.closeQuietly()rawSocket nullsink nullsource nulleventListener.connectEnd(call, route.socketAddress, route.proxy, null)} }调用createTunnelRequest创建一个通道确认的请求调用connectSocket创建socket连接createTunnel创建一个隧道在 21 次重试范围内进行 socket 和 tunnel 的连接。如果 createTunnel 返回是 null 说明隧道建立成功。 Throws(IOException::class) private fun createTunnelRequest(): Request {val proxyConnectRequest Request.Builder().url(route.address.url).method(CONNECT, null).header(Host, route.address.url.toHostHeader(includeDefaultPort true)).header(Proxy-Connection, Keep-Alive) // For HTTP/1.0 proxies like Squid..header(User-Agent, userAgent).build()val fakeAuthChallengeResponse Response.Builder().request(proxyConnectRequest).protocol(Protocol.HTTP_1_1).code(HTTP_PROXY_AUTH).message(Preemptive Authenticate).body(EMPTY_RESPONSE).sentRequestAtMillis(-1L).receivedResponseAtMillis(-1L).header(Proxy-Authenticate, OkHttp-Preemptive).build()val authenticatedRequest route.address.proxyAuthenticator.authenticate(route, fakeAuthChallengeResponse)return authenticatedRequest ?: proxyConnectRequest }这个过程构建了构建了一个代理用的proxyConnectRequest 连接请求对象以及一个虚假的响应这个响应会包含proxyConnectRequest。然后通过设置的proxyAuthenticator 进行权限校验。 Throws(IOException::class) private fun createTunnel(readTimeout: Int,writeTimeout: Int,tunnelRequest: Request,url: HttpUrl ): Request? {var nextRequest tunnelRequest// 拼接CONNECT命令val requestLine CONNECT ${url.toHostHeader(includeDefaultPort true)} HTTP/1.1while (true) {val source this.source!!val sink this.sink!!//对应http/1.1 编码HTTP请求并解码HTTP响应val tunnelCodec Http1ExchangeCodec(null, this, source, sink)source.timeout().timeout(readTimeout.toLong(), MILLISECONDS)sink.timeout().timeout(writeTimeout.toLong(), MILLISECONDS)//发送CONNECT请求打开隧道连接tunnelCodec.writeRequest(nextRequest.headers, requestLine)//完成连接tunnelCodec.finishRequest()//构建response操控的是inputStream流val response tunnelCodec.readResponseHeaders(false)!!.request(nextRequest).build()tunnelCodec.skipConnectBody(response)when (response.code) {HTTP_OK - {if (!source.buffer.exhausted() || !sink.buffer.exhausted()) {throw IOException(TLS tunnel buffered too many bytes!)}return null}HTTP_PROXY_AUTH - {nextRequest route.address.proxyAuthenticator.authenticate(route, response)?: throw IOException(Failed to authenticate with proxy)if (close.equals(response.header(Connection), ignoreCase true)) {return nextRequest}}else - throw IOException(Unexpected response code for CONNECT: ${response.code})}} }establishProtocol private fun establishProtocol(connectionSpecSelector: ConnectionSpecSelector,pingIntervalMillis: Int,call: Call,eventListener: EventListener ) {if (route.address.sslSocketFactory null) {if (Protocol.H2_PRIOR_KNOWLEDGE in route.address.protocols) {socket rawSocketprotocol Protocol.H2_PRIOR_KNOWLEDGEstartHttp2(pingIntervalMillis)return}socket rawSocketprotocol Protocol.HTTP_1_1return}eventListener.secureConnectStart(call)connectTls(connectionSpecSelector)eventListener.secureConnectEnd(call, handshake)if (protocol Protocol.HTTP_2) {startHttp2(pingIntervalMillis)} }判断route.address.sslSocketFactory null如果为true的话则说明该请求为http请求 如果http请求里包涵了“h2_prior_knowledge”协议代表是一个支持明文的http2请求所以仍然开启的是http2的连接如果http请求里不包涵了“h2_prior_knowledge”协议则正常建立http连接如果route.address.sslSocketFactory null如果为false的话则说明该请求为https请求 建立TLS连接建立http2连接 connectTls private void connectTls(ConnectionSpecSelector connectionSpecSelector) throws IOException {Address address route.address();SSLSocketFactory sslSocketFactory address.sslSocketFactory();boolean success false;SSLSocket sslSocket null;try {sslSocket (SSLSocket) sslSocketFactory.createSocket(rawSocket, address.url().host(), address.url().port(), true);ConnectionSpec connectionSpec connectionSpecSelector.configureSecureSocket(sslSocket)if (connectionSpec.supportsTlsExtensions()) {Platform.get().configureTlsExtensions(sslSocket, address.url().host(), address.protocols());}sslSocket.startHandshake();SSLSession sslSocketSession sslSocket.getSession();Handshake unverifiedHandshake Handshake.get(sslSocketSession);if (!address.hostnameVerifier().verify(address.url().host(), sslSocketSession)) {ListCertificate peerCertificates unverifiedHandshake.peerCertificates();if (!peerCertificates.isEmpty()) {X509Certificate cert (X509Certificate) peerCertificates.get(0);throw new SSLPeerUnverifiedException(Hostname address.url().host() not verified: \n certificate: CertificatePinner.pin(cert) \n DN: cert.getSubjectDN().getName() \n subjectAltNames: OkHostnameVerifier.allSubjectAltNames(cert));} else {throw new SSLPeerUnverifiedException(Hostname address.url().host() not verified (no certificates));}}address.certificatePinner().check(address.url().host(),unverifiedHandshake.peerCertificates());String maybeProtocol connectionSpec.supportsTlsExtensions()? Platform.get().getSelectedProtocol(sslSocket): null;socket sslSocket;source Okio.buffer(Okio.source(socket));sink Okio.buffer(Okio.sink(socket));handshake unverifiedHandshake;protocol maybeProtocol ! null? Protocol.get(maybeProtocol): Protocol.HTTP_1_1;success true;} catch (AssertionError e) {...} finally {...}}将刚刚得到的socket通过sslSocketFactory进行包裹得到一个新的sslSocket调用configureSecureSocket对sslSocket进行配置协议。通过supportsTlsExtensions方法查看是否支持TLS拓展调用sslSocket.startHandshake()方法开始握手协议判断!address.hostnameVerifier().verify(address.url().host(), sslSocketSession)对sslSocket的地址与主机地址进行校验确保一致可用。开始 证书校验将刚才完成握手和协议校验的sslSocket保存起来并且获得用于IO传输的source、sink Throws(IOException::class) private fun startHttp2(pingIntervalMillis: Int) {val socket this.socket!!val source this.source!!val sink this.sink!!socket.soTimeout 0 val http2Connection Http2Connection.Builder(client true, taskRunner TaskRunner.INSTANCE).socket(socket, route.address.url.host, source, sink).listener(this).pingIntervalMillis(pingIntervalMillis).build()this.http2Connection http2Connectionthis.allocationLimit Http2Connection.DEFAULT_SETTINGS.getMaxConcurrentStreams()http2Connection.start() }这个拦截器的主要作用是获取一个活跃可用连接 首先从RealCall对象中获取如果找到直接返回如果从RealCall对象没有获取到 则再从连接池中查找如果找到也是直接返回如果从连接池中没有找到则通过路由再次在连接池中查询如果找到也是直接返回如果从连接池中再次没有找到那么就创建一个RealConnection对象然后创建Socket连接封装地址信息并将该连接添加到连接池中最后进行返回 NetWorkInterceptor网络连接器 CallServerInterceptor(请求拦截器) Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response {val realChain chain as RealInterceptorChainval exchange realChain.exchange!!val request realChain.requestval requestBody request.bodyval sentRequestMillis System.currentTimeMillis()exchange.writeRequestHeaders(request)var invokeStartEvent truevar responseBuilder: Response.Builder? nullif (HttpMethod.permitsRequestBody(request.method) requestBody ! null) {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()) {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()}if (responseBuilder null) {responseBuilder exchange.readResponseHeaders(expectContinue false)!!if (invokeStartEvent) {exchange.responseHeadersStart()invokeStartEvent false}}var response responseBuilder.request(request).handshake(exchange.connection.handshake()).sentRequestAtMillis(sentRequestMillis).receivedResponseAtMillis(System.currentTimeMillis()).build()var code response.codeif (code 100) {responseBuilder exchange.readResponseHeaders(expectContinue false)!!if (invokeStartEvent) {exchange.responseHeadersStart()}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) {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 }exchange.writeRequestHeaders(request)写入请求头信息判断请求方式是不是GET或HEAD,如果不是则需要传入请求体接着判断请求头中的Expect值是否为100-continue如果是的话则会读取响应体的头部信息如果读出的Response.Builder为空接着判断 requestBody.isDuplex()如果为true的话则刷新缓冲区通过exchange.createRequestBody(request, true).buffer()创建bufferedRequestBody往请求的requestBody写入数据如果为false的话通过exchange.createRequestBody(request, true).buffer()创建bufferedRequestBody写入输出流中发送数据。如果请求方式是GET或HEAD的话则没有请求体。如果requestBody为空也就是没有请求体或者requestBody.isDuplex()为false的话则结束请求。如果responseBuilder为空的话则调用exchange.readResponseHeaders方法获取响应体判断响应体的code是否为100如果响应体为100 则是说后面还有数据需要传输则会重新调用 exchange.readResponseHeaders方法再次生成响应体判断code是否为101 并且 为websocekt请求如果是的话则生成一个空的response否则就会通过exchange.openResponseBody(response)读取response中的数据生成一个响应体。最后判断code是否为204、205并且响应体的body为空的话则抛出异常否则正常返回 。。。。。。。省略 参考 Overview - OkHttp OkHttp-源码分析(一) - 掘金 OkHttp-源码分析(二) - 掘金 OkHttp-源码分析(三) - 掘金 OKHTTP 源码分析1调用流程梳理_okhttpclient().newbuilder().build();-CSDN博客
http://www.zqtcl.cn/news/351391/

相关文章:

  • 青海住房和城乡建设部网站wordpress php7.3
  • 网站后台重置密码怎么做360网站怎么做网址链接
  • 广告网站建设及推广网站建设怎样推广
  • 做网站使网页不居中滁州注册公司流程和费用
  • 做网站广告经营者个性定制网站
  • 网站开发 北京外包公司软件公司网站建设
  • 网络认证入口seo免费诊断
  • 十大知名博客网站郑州企业建站公司定制
  • 视频网站如何做引流网站首页 关键词
  • 建设机械网站精英大港做网站
  • 潜山网站建设公司哪里有wordpress相册投票插件
  • 网站建设制作过程网站添加支付功能
  • 网站制作字体即墨公司做网站
  • vue 做pc网站可以吗哪个网站买域名便宜
  • 做销售网站那家好金华住房与城乡建设部网站
  • apple私人免费网站怎么下载无锡网站建设技术
  • 移动应用网站开发阶段作业信息型网站有哪些
  • 监控直播网站开发网站建设与管理总结
  • 青岛城阳网站设计免费网站成品
  • 做服装外贸的网站ghost wordpress
  • 建设银行的网站为什么这么卡网页设计用啥软件
  • 电子商务 网站开发南阳网网站建设
  • 中小型企业网络拓扑图及配置株洲seo网站推广
  • 中国镇江网站如何搭建自己的网址
  • wordpress 自动广告seo搜索引擎优化原理
  • 区块链网站用vue.js做怎么样长春站建筑
  • 集团公司门户网站建设adsl做网站
  • 山东建设监理协会官方网站茂名建站公司模板
  • 烟台做网站案例创业网站推广怎么做
  • php项目网站建设方案书专做药材的网站有哪些