OkHttp现在应该算是最火的Http第三方库,Retrofit底层也是使用OkHttp
OkHttp官网地址:http://square.github.io/okhttp/
OkHttp GitHub地址:https://github.com/square/okhttp
网络访问的高效性要求,可以说是为高效而生
使用OkHttp很简单。它的请求/响应API具有fluent builders(链接构造)和不变性。它既支持同步阻塞调用,也支持带有回调的异步调用。
OkHttp中用户可传入的interceptor分为两类:
拦截器 | 作用 |
---|---|
用户自定义的拦截器 | 用户实现的一些自定义拦截功能,如记录日志 |
retryAndFollowUpInterceptor | 重试和重定向拦截器,主要负责网络失败重连 |
BridgeInterceptor | 主要是桥接应用层和网络层: 添加必要的请求头信息【encoding,cookie,userAgent等】、gzip处理等 |
CacheInterceptor | 缓存拦截器,主要负责拦截缓存 |
ConnectInterceptor | 网络连接拦截器,主要负责正式开启http请求 |
CallServerInterceptor | 负责发送网络请求和读取网络响应 |
getResponseWithInterceptorChain()是okhttp中的精髓设计之一。
通过拦截器链对请求数据和返回数据进行处理,内部采用责任链模式,将每一个拦截器对应负责的处理任务进行严格分配,最后将交易结果返回并回调暴露给调用者的接口上,代码如下:
@Throws(IOException::class) internal fun getResponseWithInterceptorChain(): Response { // Build a full stack of interceptors. val interceptors = mutableListOf<Interceptor>() interceptors += client.interceptors interceptors += RetryAndFollowUpInterceptor(client) interceptors += BridgeInterceptor(client.cookieJar) interceptors += CacheInterceptor(client.cache) interceptors += ConnectInterceptor if (!forWebSocket) { interceptors += client.networkInterceptors } interceptors += CallServerInterceptor(forWebSocket) val chain = RealInterceptorChain( call = this, interceptors = interceptors, index = 0, exchange = null, request = originalRequest, connectTimeoutMillis = client.connectTimeoutMillis, readTimeoutMillis = client.readTimeoutMillis, writeTimeoutMillis = client.writeTimeoutMillis ) var calledNoMoreExchanges = false try { val response = chain.proceed(originalRequest) if (isCanceled()) { response.closeQuietly() throw IOException("Canceled") } return response } catch (e: IOException) { calledNoMoreExchanges = true throw noMoreExchanges(e) as Throwable } finally { if (!calledNoMoreExchanges) { noMoreExchanges(null) } }
整个请求过程通过RealInterceptorChain#proceed来连接,在每个interceptor中调用下一个interceptor来完成整个请求流程,并且在回到当前interceptor后完成响应处理。
在调用拦截器的intercept(next)方法前,会copy当前的RealInterceptorChain【只有index不同】赋值给next变量。
只有当前拦截器的response返回有结果时,才会执行下一个拦截器,因此得出结论:下一个拦截器依赖于当前拦截器的返回,可以保证拦截器的依次执行
@Throws(IOException::class) override fun proceed(request: Request): Response { check(index < interceptors.size) calls++ if (exchange != null) { check(exchange.finder.sameHostAndPort(request.url)) { "network interceptor ${interceptors[index - 1]} must retain the same host and port" } check(calls == 1) { "network interceptor ${interceptors[index - 1]} must call proceed() exactly once" } } // Call the next interceptor in the chain. 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") if (exchange != null) { check(index + 1 >= interceptors.size || next.calls == 1) { "network interceptor $interceptor must call proceed() exactly once" } } check(response.body != null) { "interceptor $interceptor returned a response with no body" } return response }
至此,okhttp的整体架构分析完毕,可以跟着源码一步步去理解,去了解okhttp的设计思想,然后应用到项目开发中。
okhttp是一个很庞大的一个框架,本文仅仅从请求流程和拦截器方面做了简单的分析,内部的实现逻辑和思想都很值得认真思考和细细品味