OkHttp任务调度流程:

1. OkHttpClient构建过程分析

案例:

OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new CustomInterceptor()).cache(new Cache(cacheDir, cacheSize)).readTimeout(1000, TimeUnit.MILLISECONDS).writeTimeout(1000, TimeUnit.MILLISECONDS).build();

 OkHttp使用建造者模式来构建一个OkHttpClient(客户端)对象,完成以下配置:

  • a. 指定自定义拦截器Interceptor;
  • b. 指定Cache缓存目录;
  • c. 指定DNS域名解析服务器、代理服务器Proxy;
  • d. 指定超时时间(请求超时、连接超时、读超时、写超时);
  • e. 创建一个任务调度器Dispatcher;
  • f. 创建一个连接池ConnectionPool(复用Socket连接)等等;
open class OkHttpClient internal constructor(builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {/**** 1. 创建网络请求客户端OkHttpClient,分为两步* (1) 创建构建者OkHttpClient.Builder,并配置构建参数;* (2) 由构建者构建客户端OkHttpClient* var client = OkHttpClient.newBuilder()*              .addInterceptor(...)*              .dns(...)*              .proxy(...)*              .build()*///(1)创建构建客户端的构建者对象// 即var builder = OkHttpClient.newBuilder()// 在Builder构建者的构造函数中,初始化用于构建OkHttpClient对象的各类参数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            // 请求失败时是否重试,默认为trueinternal var authenticator: Authenticator = Authenticator.NONEinternal var followRedirects = trueinternal var followSslRedirects = trueinternal var cookieJar: CookieJar = CookieJar.NO_COOKIES // 持久连接Cookieinternal var cache: Cache? = null                        // 缓存internal var dns: Dns = Dns.SYSTEM                       // 域名解析器internal var proxy: Proxy? = null                        // 访问代理internal var proxySelector: ProxySelector? = nullinternal var proxyAuthenticator: Authenticator = Authenticator.NONEinternal var socketFactory: SocketFactory = SocketFactory.getDefault()internal var sslSocketFactoryOrNull: SSLSocketFactory? = nullinternal var x509TrustManagerOrNull: X509TrustManager? = nullinternal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECSinternal var protocols: List<Protocol> = DEFAULT_PROTOCOLSinternal var hostnameVerifier: HostnameVerifier = OkHostnameVerifierinternal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULTinternal var certificateChainCleaner: CertificateChainCleaner? = nullinternal var callTimeout = 0          // 请求超时时间internal var connectTimeout = 10_000  // 连接超时时间internal var readTimeout = 10_000     // 写操作超时时间internal var writeTimeout = 10_000    // 读操作超时时间internal var pingInterval = 0internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZEinternal var routeDatabase: RouteDatabase? = null//(2)使用构建者OkHttpClient.Builder构建客户端OkHttpClient对象// 在OkHttpClient构造方法中,会依次将构建者配置的参数// 赋值给OkHttpClientfun build(): OkHttpClient = OkHttpClient(this)
}

2. Request构建过程分析

示例代码:

// GET请求
Request request = new Request.Builder().url("https://github.com/").header("User-Agent", "OkHttp Headers.java").addHeader("Accept", "application/json; q=0.5").addHeader("Accept", "application/vnd.github.v3+json").build();// POST请求(发送String)
public static final MediaType MEDIA_TYPE_MARKDOWN= MediaType.parse("text/x-markdown; charset=utf-8");
String postBody = ""+ "Releases\n"+ "--------\n"+ "\n"+ " * _1.0_ May 6, 2013\n"+ " * _1.1_ June 15, 2013\n"+ " * _1.2_ August 11, 2013\n";Request request = new Request.Builder().url("https://api.github.com/markdown/raw").post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody)).build();// POST请求(发送Stream)
RequestBody requestBody = new RequestBody() {@Override public MediaType contentType() {return MEDIA_TYPE_MARKDOWN;}@Override public void writeTo(BufferedSink sink) throws IOException {sink.writeUtf8("Numbers\n");sink.writeUtf8("-------\n");for (int i = 2; i <= 997; i++) {sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));}}private String factor(int n) {for (int i = 2; i < n; i++) {int x = n / i;if (x * i == n) return factor(x) + " × " + i;}return Integer.toString(n);}
};Request request = new Request.Builder().url("https://api.github.com/markdown/raw").post(requestBody).build();// POST请求(发送文件)
File file = new File("README.md");Request request = new Request.Builder().url("https://api.github.com/markdown/raw").post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file)).build();// POST请求(发送Form表单-键值对)
RequestBody formBody = new FormBody.Builder().add("search", "Jurassic Park").build();
Request request = new Request.Builder().url("https://en.wikipedia.org/w/index.php").post(formBody).build();// POST请求(multipart数据)
RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("title", "Square Logo").addFormDataPart("image", "logo-square.png", RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png"))).build();Request request = new Request.Builder().header("Authorization", "Client-ID " + IMGUR_CLIENT_ID).url("https://api.imgur.com/3/image").post(requestBody).build();

 OkHttp使用建造者模式来构建一个Request HTTP请求,完成以下配置:

  • a. 指定HTTP请求HttpUrl;
  • b. 指定HTTP请求Headers(注:也是使用建造者模式构建Headers.Builder);
  • c. 指定HTTP请求方法method,默认为GET方法;
  • d. 指定HTTP请求实体RequestBody,针对于POST方法。
class Request internal constructor(@get:JvmName("url") val url: HttpUrl,@get:JvmName("method") val method: String,@get:JvmName("headers") val headers: Headers,@get:JvmName("body") val body: RequestBody?,internal val tags: Map<Class<*>, Any>
) {/***  构建网络请求对象Requst,分为两步:*  (1)创建构建Request对象的构建者Request.Builder;*  (2)使用构建者构建Request对象*  var request = Request.Builder()*                .url(...)*                .header(...)*                .build()*/// (1)创建构建Request对象的构建者Request.Builder// var requestBuilder = Request.newBuilder()open class Builder {internal var url: HttpUrl? = null      // host域名internal var method: String            // 请求方法,默认为"GET"internal var headers: Headers.Builder  // 请求头Headersinternal var body: RequestBody? = null // 请求实体RequestBodyinternal var tags: MutableMap<Class<*>, Any> = mutableMapOf()// tag集合constructor() {this.method = "GET"this.headers = Headers.Builder()}// 指定HTTP头部open fun header(name: String, value: String) = apply {headers[name] = value}open fun addHeader(name: String, value: String) = apply {headers.add(name, value)}// 指定HTTP请求方法open fun get() = method("GET", null)open fun head() = method("HEAD", null)open fun post(body: RequestBody) = method("POST", body)@JvmOverloadsopen fun delete(body: RequestBody? = EMPTY_REQUEST) = method("DELETE", body)open fun put(body: RequestBody) = method("PUT", body)open fun patch(body: RequestBody) = method("PATCH", body)// (2) 使用构建者构建Request对象open fun build(): Request {return Request(checkNotNull(url) { "url == null" },method,headers.build(),body,tags.toImmutableMap())}
}

3. 网络通信过程分析

案例

// 同步请求
Response response = client.newCall(request).execute();// 异步请求
client.newCall(request).enqueue(new Callback() {@Override public void onFailure(Call call, IOException e) {e.printStackTrace();}@Override public void onResponse(Call call, Response response) throws IOException {ResponseBody responseBody = response.body());...}
});

 任务调度器、责任链模式(拦截器链)。

(1) 获取网络请求器Call对象;

/**
* 1. 创建发起网络请求的Call对象,通过它可以执行同步请求和异步请求
* 调用客户端OkHttpClient.newCall(request)方法实现
* Call是一个接口,它的实现类为RealCall,它是衔接应用层与网络层的桥梁
*/
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

(2) 同步请求

class RealCall(val client: OkHttpClient,/** The application's original request unadulterated by redirects or auth headers. */val originalRequest: Request,val forWebSocket: Boolean
) : Call {// 3-1 发起同步网络请求override fun execute(): Response {// (1) 检查当前Call是否被执行// 如果正在执行,抛出"IllegalStateException"异常check(executed.compareAndSet(false, true)) { "Already Executed" }timeout.enter()callStart()try {// (2) 调用任务调度器的executed方法// 将Call任务添加到同步执行队列中即runningSyncCalls(ArrayDeque<RealCall>())// 即runningSyncCalls.add(call)client.dispatcher.executed(this)//(3)通过拦截器链获得响应Response// 并直接返回(注意:执行完getResponseWithInterceptorChain()后,会接着执行finally语句,最后再执行return)return getResponseWithInterceptorChain()} finally {//(4)网络请求完毕或者异常// 从runningSyncCalls队列中移除当前任务client.dispatcher.finished(this)}}
}class Dispatcher constructor() {...// 同步执行队列// ArrayDeque即可作为Stack,也可作为Queue,它是线程非安全的private val runningSyncCalls = ArrayDeque<RealCall>()@Synchronized internal fun executed(call: RealCall) {// 将Call任务添加到同步执行队列中ArrayDequerunningSyncCalls.add(call)}private fun <T> finished(calls: Deque<T>, call: T) {val idleCallback: Runnable?synchronized(this) {// a. 从对应队列中移除任务RealCall(同步任务)、AsyncCall(异步任务,Runnable)if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!")idleCallback = this.idleCallback}//  b. 对于异步请求来说,遍历等待队列//  从等待队列中取新的任务,插入到执行队列中val isRunning = promoteAndExecute()if (!isRunning && idleCallback != null) {idleCallback.run()}}}

(3) 异步请求

class RealCall(val client: OkHttpClient,/** The application's original request unadulterated by redirects or auth headers. */val originalRequest: Request,val forWebSocket: Boolean
) : Call {// 3-2 发起异步网络请求override fun enqueue(responseCallback: Callback) {// (1) 检查当前Call是否被执行// 如果正在执行,抛出"IllegalStateException"异常check(executed.compareAndSet(false, true)) { "Already Executed" }callStart()//(2) 调用任务调度器的enqueue方法// 注:AsyncCall是RealCall的内部类,继承于Runnableclient.dispatcher.enqueue(AsyncCall(responseCallback))}
}
  • Dispatcher:执行任务调度 (执行队列、等待队列)
class Dispatcher constructor() {// 异步等待队列private val readyAsyncCalls = ArrayDeque<AsyncCall>()/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */// 异步执行队列private val runningAsyncCalls = ArrayDeque<AsyncCall>()/** Running synchronous calls. Includes canceled calls that haven't finished yet. */// 同步执行队列// ArrayDeque即可作为Stack,也可作为Queue,它是线程非安全的private val runningSyncCalls = ArrayDeque<RealCall>()constructor(executorService: ExecutorService) : this() {this.executorServiceOrNull = executorService}internal fun enqueue(call: AsyncCall) {synchronized(this) {// 3-2-(2)-a 首先,将异步任务AsyncCall添加到等待队列中readyAsyncCalls.add(call)if (!call.call.forWebSocket) {val existingCall = findExistingCallWithHost(call.host)if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)}}// 3-2-(2)-a 然后,从等待队列取任务插入到执行队列中// 再在线程池中执行新任务promoteAndExecute()}private fun promoteAndExecute(): Boolean {this.assertThreadDoesntHoldLock()val executableCalls = mutableListOf<AsyncCall>()val isRunning: Boolean// b-1 遍历等待队列,决定是否将其添加到可执行队列中(线程安全)// - 如果执行队列中正在执行的任务数量>=maxRequests,拒绝添加任何新任务到执行队列;// - 如果当前Host的请求数超过maxRequestsPerHost,拒绝本次新任务到执行队列;// - 否则,将等待队列中的任务添加到执行队列,并从等待队列删除任务synchronized(this) {val i = readyAsyncCalls.iterator()while (i.hasNext()) {val asyncCall = i.next()// 最大并发量判断,maxRequests=64if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.// Host允许最大请求数判断,maxRequestsPerHost = 5if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.// 从等待队列移除i.remove()asyncCall.callsPerHost.incrementAndGet()// 将新任务添加到executableCalls列表中executableCalls.add(asyncCall)// 将其添加到执行队列中runningAsyncCalls.add(asyncCall)}isRunning = runningCallsCount() > 0}// b-2 遍历executableCalls列表// 依次将要执行的新任务放在线程池中执行,调用asyncCall.executeOn实现// (1)将新任务插入到线程池执行, executorService.execute(this);// (2)执行异常或执行完毕均尝试从等待队列中取新任务任务, client.dispatcher.finished(this);// 注:具体的任务执行流程,请看AsyncCall.run()方法for (i in 0 until executableCalls.size) {val asyncCall = executableCalls[i]asyncCall.executeOn(executorService)}return isRunning}
}
  • AsyncCall:继承于Runnable,被添加到线程池中执行,子线程中执行拦截器链逻辑,即getResponseWithInterceptorChain
inner class AsyncCall(private val responseCallback: Callback
) : Runnable {fun executeOn(executorService: ExecutorService) {client.dispatcher.assertThreadDoesntHoldLock()var success = falsetry {// 将任务添加到线程池executorService.execute(this)success = true} catch (e: RejectedExecutionException) {val ioException = InterruptedIOException("executor rejected")ioException.initCause(e)noMoreExchanges(ioException)// 如果本次任务执行异常,出现异常回调responseCallback接口的onFailure方法responseCallback.onFailure(this@RealCall, ioException)} finally {// 如果本次任务执行异常,从等待队列中取下一个任务if (!success) {client.dispatcher.finished(this) // This call is no longer running!}}}// 3-2 异步任务执行流程override fun run() {threadName("OkHttp ${redactedUrl()}") {var signalledCallback = falsetimeout.enter()try {// (1)调用拦截器链得到响应数据reponseval response = getResponseWithInterceptorChain()signalledCallback = true// (2)请求成功,将异步请求响应结果回调出去responseCallback.onResponse(this@RealCall, response)} catch (e: IOException) {if (signalledCallback) {// Do not signal the callback twice!Platform.get().log("Callback failure for ${toLoggableString()}", Platform.INFO, e)} else {//(3)请求失败,将异常信息回调出去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 {// (4)从等待队列中取下一批任务添加到线程池中执行// 并更新等待队列和执行队列的信息client.dispatcher.finished(this)}}}
}

(4) 拦截器链功能

 OkHttp框架使用责任链模式一步一步完成整个网络通信,每个拦截器有自己的功能。

  • 自定义拦截器;
  • RetryAndFollowUpInterceptor:重定向拦截器,用于处理错误和进行重定向;
  • BridgeInterceptor:桥梁拦截器,用于构建网络连接桥梁。将用户请求转换为网络请求,将网络响应转换为用户响应;
  • CacheInterceptor:缓存拦截器,用于从缓存中获取服务器请求,或者把服务器响应写入缓存中;
  • ConnectInterceptor:连接拦截器,用于打开一个Socket连接,去连接目标服务器;
  • CallServerInterceptor:请求服务器拦截器,拦截器链的最后一个拦截器,执行通过网络请求服务器,即完成Socket通信。

具体功能:

(1)RetryAndFollowUpInterceptor:重定向拦截器,用于处理错误和进行重定向;

  • a. 获取下一个要执行的拦截器BridgeInterceptor;
  • b. 开始轮询,通过BridgeInterceptor返回的用户响应respone,是否需要重定向。如果response的followUp==null,说明请求成果,返回用户响应response;否则,执行重定向请求,需要注意的时当重定向的次数超过20次抛出异常;

源码如下:

/*** 4-1 RetryAndFollowUpInterceptor拦截器* 用于处理错误和进行重定向*/@Throws(IOException::class)override fun intercept(chain: Interceptor.Chain): Response {//(1)获取下一个要执行的拦截器// 注:每一个拦截器存储的request和call信息是一致的val realChain = chain as RealInterceptorChainvar request = chain.requestval call = realChain.callvar followUpCount = 0var priorResponse: Response? = nullvar newExchangeFinder = truevar recoveredFailures = listOf<IOException>()// (2)开始轮询,即是否需要重定向,当次数超过20次抛出异常while (true) {call.enterNetworkInterceptorExchange(request, newExchangeFinder)var response: Responsevar closeActiveExchange = truetry {// a. 如果请求被取消,抛出IOExceptionif (call.isCanceled()) {throw IOException("Canceled")}// b. 调用下一个拦截器BridgeInterceptor// 将用户请求request作为参数传入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 = falsecontinue} 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 = falsecontinue}//--------------------------------------------------------------------//--------------------------------------------------------------------// //  处理Bridge拦截器返回的用户响应  //--------------------------------------------------------------------//--------------------------------------------------------------------// Attach the prior response if it exists. Such responses never have a body.// c. 检测前一个Responseif (priorResponse != null) {response = response.newBuilder().priorResponse(priorResponse.newBuilder().body(null).build()).build()}val exchange = call.interceptorScopedExchangeval followUp = followUpRequest(response, exchange)// d. followUp为null,表示不要重定向,释放资源并且返回responseif (followUp == null) {if (exchange != null && exchange.isDuplex) {call.timeoutEarlyExit()}closeActiveExchange = falsereturn response}val followUpBody = followUp.bodyif (followUpBody != null && followUpBody.isOneShot()) {closeActiveExchange = falsereturn response}// e. 否则,关闭response的body// 并重定向,注意,最大重定向次数不能超过20次response.body?.closeQuietly()if (++followUpCount > MAX_FOLLOW_UPS) {throw ProtocolException("Too many follow-up requests: $followUpCount")}request = followUppriorResponse = response} finally {call.exitNetworkInterceptorExchange(closeActiveExchange)}}}

(2)BridgeInterceptor:桥梁拦截器,用于构建网络连接桥梁。将用户请求转换为网络请求,将网络响应转换为用户响应;

  • a. 将用户请求userRequest将转为服务器请求request,使用建造者模式实现;
  • b. 调用下一个拦截器CacheInterceptor,并将服务器请求作为参数传入;
  • c. 将网络响应response转换为用户响应,其中response由CahceInterceptor返回。

源码如下:

/*** 4-2 BridgeInterceptor拦截器* 构建网络连接桥梁。将用户请求转换为网络请求,将网络响应转换为用户响应*/@Throws(IOException::class)override fun intercept(chain: Interceptor.Chain): Response {// (1)将用户请求userRequest将转为网络请求// "Connection": "Keep-Alive"// "Transfer-Encoding": "chunked"// "Accept-Encoding": "gzip"// ...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")}// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing// the transfer stream.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)}// (2) 调用下一个拦截器// 并将服务器请求作为参数传入CacheInterceptorval networkResponse = chain.proceed(requestBuilder.build())cookieJar.receiveHeaders(userRequest.url, networkResponse.headers)//--------------------------------------------------------------------//--------------------------------------------------------------------// //  处理Cache拦截器返回的网络响应  //--------------------------------------------------------------------//--------------------------------------------------------------------// (3) 将网络响应转换为用户响应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()responseBuilder.headers(strippedHeaders)val contentType = networkResponse.header("Content-Type")responseBuilder.body(RealResponseBody(contentType, -1L, gzipSource.buffer()))}}return responseBuilder.build()}

(3)CacheInterceptor:缓存拦截器,用于从缓存中获取服务器请求,或者把服务器响应写入缓存中;

  • a. 根据请求获“候选”缓存,如果Cache中有的话;
  • b. 获取缓存策略strategy,通过工厂模式实现;
  • c. 检测缓存是否有效,如果网络被禁止直接返回缓存Response;
  • d. 调用下一个拦截器,即ConnectInteceptor,从网络中获取响应response;
  • e. 将网络响应返回给上一个拦截器,并更新缓存。
/*** 4-3 CacheInterceptor拦截器* 从缓存中获取服务器请求,或者把服务器响应写入缓存中*/@Throws(IOException::class)override fun intercept(chain: Interceptor.Chain): Response {val call = chain.call()// (1) 根据请求获“候选”缓存,如果Cache中有的话val cacheCandidate = cache?.get(chain.request())val now = System.currentTimeMillis()// (2) 获取缓存策略strategy// 工厂模式// networkRequest----->网络请求// cacheResponse------>缓存响应结果val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute()val networkRequest = strategy.networkRequestval cacheResponse = strategy.cacheResponse// (3) 从缓存中追踪Responsecache?.trackResponse(strategy)val listener = (call as? RealCall)?.eventListener ?: EventListener.NONE// (4) 如果缓存不适用,则关闭if (cacheCandidate != null && cacheResponse == null) {// The cache candidate wasn't applicable. Close it.cacheCandidate.body?.closeQuietly()}// (5) 如果网络被禁止,且缓存为空,则返回失败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)}}// (6)如果网络被禁止,从缓存中获取响应并返回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)}// (7) 调用下一个拦截器,即ConnectInteceptor// 从网络中获取响应responsevar networkResponse: Response? = nulltry {networkResponse = chain.proceed(networkRequest)} finally {// 关闭Body,防止出现内存泄漏if (networkResponse == null && cacheCandidate != null) {cacheCandidate.body?.closeQuietly()}}//--------------------------------------------------------------------//--------------------------------------------------------------------// //  处理Connect拦截器返回的网络响应Response  //--------------------------------------------------------------------//--------------------------------------------------------------------// (8) 如果缓存中存在Response,同时检测networkResponse是否被修改// 然后再更新缓存中的数据到最新if (cacheResponse != null) {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()}}// (9) 使用网络响应networkResponse和cacheResponse// 构建responseval 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).also {if (cacheResponse != null) {// This will log a conditional cache miss only.listener.cacheMiss(call)}}}if (HttpMethod.invalidatesCache(networkRequest.method)) {try {cache.remove(networkRequest)} catch (_: IOException) {// The cache cannot be written.}}}// (10) 将(9)构建的response返回给上一个拦截器// 即桥接拦截器BridgeInterceptorreturn response}

(4)ConnectInterceptor:连接拦截器,用于打开一个Socket连接,去连接目标服务器;

  • a. 获取一个ExChange对象,即Http2ExchangeCodec,主用于对HTTP请求编码,发起Socket连接,并解码HTTP响应;
  • b. 执行下一个拦截器CallServerInterceptor,并直接返回其response。

源码如下

 /*** 4-4 ConnectInterceptor拦截器* 打开一个连接,去连接目标服务器*/@Throws(IOException::class)override fun intercept(chain: Interceptor.Chain): Response {val realChain = chain as RealInterceptorChain// (1) 获取一个ExChange对象,该对象是对Http1ExchangeCodec/Http2ExchangeCodec和下一个Chain的封装//  Http1ExchangeCodec/Http2ExchangeCodec分别对应于HTTP1.1/HTTP2.0// 主要用户对HTTP请求编码,发起Socket连接,并解码HTTP响应// Socket通信过程:// a. 发送网络请求头部headers【writeRequest】;// b. 打开一个接收器sink,写网络请求body【newKnownLengthSink或newChunkedSink】;// c. 完成写入,并关闭接收器sink;// d. 读取响应头部【readResponseHeaders】;// e. 打开数据源source,读取响应实体body【newFixedLengthSource】// f. 读取完毕,关闭数据源Sourceval exchange = realChain.call.initExchange(chain)val connectedChain = realChain.copy(exchange = exchange)// (2) 执行下一个拦截器CallServerInterceptor// 并将该拦截器的response作为本拦截器(ConnectInterceptor)的response返回给上一个拦截器return connectedChain.proceed(realChain.request)}

(5)CallServerInterceptor:请求服务器拦截器,拦截器链的最后一个拦截器,执行通过网络请求服务器,即完成Socket通信。

  • a. 获取网络访问对象Http1ExchangeCodec/Http2ExchangeCodec;
  • b. 获取网络访问请求request和body;
  • c. 打开一个Socket连接,获取一个sink对象,写入头部;
  • d. 执行Socket数据通信;
  • e. 解析Socket通信响应头部信息exchange.readResponseHeaders;
  • f. 构建最终的网络响应response,返回给上一个拦截器ConnectInterceptor。

源码如下

/*** 4-5 CallServerInterceptor拦截器* 拦截器链的最后一个拦截器,执行通过网络请求服务器,即完成Socket通信*/@Throws(IOException::class)override fun intercept(chain: Interceptor.Chain): Response {val realChain = chain as RealInterceptorChain// (1) 获取网络访问对象Http1ExchangeCodec/Http2ExchangeCodecval exchange = realChain.exchange!!// (2) 获取网络访问请求request和bodyval request = realChain.requestval requestBody = request.bodyval sentRequestMillis = System.currentTimeMillis()var invokeStartEvent = truevar responseBuilder: Response.Builder? = nullvar sendRequestException: IOException? = nulltry {// (3) 打开一个Socket连接// 获取一个sink对象,写入头部exchange.writeRequestHeaders(request)// (4) 检查是否有body的请求方法// 即请求方法不是GET和HEAD的情况if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {//如果请求头是"100-continue",等待服务器的响应if ("100-continue".equals(request.header("Expect"), ignoreCase = true)) {exchange.flushRequest()responseBuilder = exchange.readResponseHeaders(expectContinue = true)exchange.responseHeadersStart()invokeStartEvent = false}// 写入body,发送请求数据到服务端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()}} 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 {// (5) 读取响应头if (responseBuilder == null) {responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!if (invokeStartEvent) {exchange.responseHeadersStart()invokeStartEvent = false}}// (6) 构建响应Responsevar response = responseBuilder.request(request).handshake(exchange.connection.handshake()).sentRequestAtMillis(sentRequestMillis).receivedResponseAtMillis(System.currentTimeMillis()).build()var code = response.code// (7) 如果服务器返回的状态码是100,再次尝试读取具体的responseif (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)// (8) 如果是WebSocket,并且返回状态码为101,表示响应body为空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 {// (9) 读取响应实体bodyresponse.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()}")}// (10) 将最终的网络响应response返回给上一层拦截器ConnectInterceptorreturn response} catch (e: IOException) {if (sendRequestException != null) {sendRequestException.addSuppressed(e)throw sendRequestException}throw e}}

网络请求框架OkHttp4的使用与原理解析01:任务调度与拦截器分析相关推荐

  1. 你想要的系列:网络请求框架OkHttp3全解系列 - (二)OkHttp的工作流程分析

    Okhttp系列文章: 你想要的系列:网络请求框架OkHttp3全解系列 - (一)OkHttp的基本使用 你想要的系列:网络请求框架OkHttp3全解系列 - (二)OkHttp的工作流程分析 你想 ...

  2. 网络调度框架Retrofit2的使用与原理解析

     Retrofit是squareup公司的开源力作,和同属squareup公司开源的OkHttp,一个负责网络调度,一个负责网络执行,为Android开发者提供了即方便又高效的网络访问框架.Retro ...

  3. android 设置允许http请求_网络请求框架----OkHttp原理

    一.前言 在 Android 中,网络请求是一个必不可少的功能,因此就有许多代表网络请求客户端的组件库,具有代表性的有下面三种: Apache 的 HTTP 客户端组件 HttpClient. Jav ...

  4. Android 开源网络框架OKHttp4 Kotlin版本源码解析

    Android 开源网络框架OKHttp 4 解析 文章目录 Android 开源网络框架OKHttp 4 解析 1.Http2.0协议主要增加的优化点: 2.OkHttp支持的内容 3.OkHttp ...

  5. Android主流网络请求框架

    一.Volley google推出的异步网络请求框架和图片加载框架.特别适合数据量小,通信频繁的网络操作.android绝大多数都属于这种类型,但是对于数据量比较大的操作,比如:下载,就不太适用了. ...

  6. android post请求_Vue 网络请求框架 axios 使用教程

    点击上方"代码集中营",设为星标 优秀文章,第一时间送达! 前期回顾 1. Vue 学习入门指南 2. Vue 入门环境搭建 3. Visual Studio Code 使用指南 ...

  7. 如何独立开发一个网络请求框架

    (原创出处为本博客:http://www.cnblogs.com/linguanh/) 目录:   前言 准备工作  开发模式 开发原则 线程 高并发 TCP/UDP 本类介绍  开发选择 功能列表 ...

  8. android网络请求框架_2020,最新APP重构:网络请求框架

    在现在的app,网络请求是一个很重要的部分,app中很多部分都有或多或少的网络请求,所以在一个项目重构时,我会选择网络请求框架作为我重构的起点.在这篇文章中我所提出的架构,并不是所谓的 最好 的网络请 ...

  9. App 组件化/模块化之路——如何封装网络请求框架

    App 组件化/模块化之路--如何封装网络请求框架 在 App 开发中网络请求是每个开发者必备的开发库,也出现了许多优秀开源的网络请求库.例如 okhttp retrofit android-asyn ...

最新文章

  1. 传递字符串_一道经典面试题:字符串在Java中如何通过“引用”传递
  2. Nginx——负载均衡
  3. 音频数据建模全流程代码示例:通过讲话人的声音进行年龄预测
  4. [云炬创业基础笔记]盈利构造
  5. 【无人驾驶】基于毫米波雷达的自动紧急刹车系统设计
  6. android 保存图片出现2张_OriCell第三届细胞培养图片大赛来啦~ - 实验动物
  7. android9.0变化,十年巨变 Android 1.0对比Android 9
  8. mysql bin 分析_mysql bin log 分析
  9. oracle 12 跟踪,Oracle 12C 块修改跟踪(Block chage tracking) 功能
  10. Lattice - 规划模块 1.采样轨迹 2.计算轨迹cost 3 循环检测筛选轨迹
  11. 天翼,有毒?“校园客户端挂马事件”雷锋网独家解析
  12. 改变linux环境背景色,改变Linux 字体和背景颜色
  13. ArduinoUNO实战-第七章-PWM调光
  14. 台式计算机有无线网卡吗,台式机无线网卡怎么用?图解在这自己收藏
  15. 南京商品房信息在哪里查询(查备案价)
  16. Mac 配置maven
  17. 最简单明了的QT服务器搭建
  18. iphone4 快捷键整理
  19. 预处理--python实现用随机森林评估特征的重要性
  20. 苹果xr十大隐藏功能_苹果手机有哪些隐藏小功能?【建议收藏】

热门文章

  1. 河南电视台:让中原文化“云”中起舞
  2. 身为企业网管需要明白的三个道理
  3. 更好的基金定投策略:价值平均
  4. Github项目推荐-图神经网络(GNN)相关资源大列表
  5. java_Tomcat环境变量的配置步骤
  6. 信息系统项目管理师第四版知识摘编:第2章 信息技术发展
  7. cannot find coclass for interface....解决方法
  8. python将灰度图保存为8bit彩色图
  9. 没有胆量,有天赋也是白费。Without guts,talent is wasted.
  10. 谈家庭网关产品的自动化(一)