从okhttp最基本的使用方式解析okhttp
okhttp的使用很简单
- 导入依赖
implementation 'com.squareup.okhttp3:okhttp:4.5.0'
使用的是4.x跟3.x版本相比代码已经转变为kotlin - new OkHttpClient;
- 构造Request对象;
- 通过前两步中的对象构建Call对象;
- 通过Call.enqueue(Callback)方法来提交异步请求;
val mOk = OkHttpClient()
val request = Request.Builder()
.url("请求地址")
.get()//请求方式
.build()
val call = mOk.newCall(request)
call.enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
Log.e(TAG, "请求成功")
}
override fun onFailure(call: Call, e: IOException) {
Log.e(TAG, "请求失败")
}
})
步骤一:创建okhttpClicent实例
val mOk = OkHttpClient()
okhttp在这一步内进行了很多的默认配置,都在OkHttpClient()构造方法内的Builder()对象中,如连接超时,读取超时,写入超时,请求协议,重连,缓存等,所以如果要配置这些的话就要通过OkHttpClient.Builder()
来构建OkhttpClient()对象。如果没有特别要求,使用默认的就可以,一句代码就搞定,使用起来是很方便的(●ˇ∀ˇ●)
class Builder constructor() {
//调度器
internal var dispatcher: Dispatcher = Dispatcher()
//连接池管理HTTP和HTTP/2连接的重用以减少网络延迟
internal var connectionPool: ConnectionPool = ConnectionPool()
//存储拦截器实例,本质责任链模式
internal val interceptors: MutableList<Interceptor> = mutableListOf()
internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
//事件侦听器工厂 监听http通信
internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
//允许失败重连
internal var retryOnConnectionFailure = true
internal var authenticator: Authenticator = Authenticator.NONE
//允许重定向
internal var followRedirects = true
//是否允许 SSL 重定向
internal var followSslRedirects = true
//存储cookie 不设置则不存储 cookie。
internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
//缓存
internal var cache: Cache? = null
internal var dns: Dns = Dns.SYSTEM
internal var proxy: Proxy? = null
internal var proxySelector: ProxySelector? = null
internal var proxyAuthenticator: Authenticator = Authenticator.NONE
internal var socketFactory: SocketFactory = SocketFactory.getDefault()
internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
internal var x509TrustManagerOrNull: X509TrustManager? = null
internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
//请求协议 internal val DEFAULT_PROTOCOLS = immutableListOf(HTTP_2, HTTP_1_1)
internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS
internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
internal var certificateChainCleaner: CertificateChainCleaner? = null
//调度超时时间
internal var callTimeout = 0
//连接超时时间
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
在OkhttpClick构造方法内有一个调度器,主要有①并发执行的最大请求数②每个主机并发请求的最大数③有一个线程池,这个线程池内理论上允许的线程数是不受限制的,空闲线程超过60秒会自动被回收,线程池为了解决执行大量异步任务时,减少每个任务的调用开销,所提供的一种限制和管理资源的方法 ④调度器内还定义了三个队列两个异步一个同步⑤取消请求
/**
* 并发执行的最大请求数
*/
@get:Synchronized var maxRequests = 64
set(maxRequests) {
require(maxRequests >= 1) { "max < 1: $maxRequests" }
synchronized(this) {
field = maxRequests
}
promoteAndExecute()
}
/**
* 每个主机并发执行的最大请求数
*/
@get:Synchronized var maxRequestsPerHost = 5
set(maxRequestsPerHost) {
require(maxRequestsPerHost >= 1) { "max < 1: $maxRequestsPerHost" }
synchronized(this) {
field = maxRequestsPerHost
}
promoteAndExecute()
}
private var executorServiceOrNull: ExecutorService? = null
@get:Synchronized
@get:JvmName("executorService") val executorService: ExecutorService
get() {
if (executorServiceOrNull == null) {
/**
* 线程池
* 第一个参数要保留的线程,第二个参数允许的线程数,第三个参数多余空闲线程在终止前等待新任务的
* 最长时间
*/
executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
}
return executorServiceOrNull!!
}
/**按运行顺序准备异步调用 */
private val readyAsyncCalls = ArrayDeque<AsyncCall>()
/** 正在运行异步调用。 */
private val runningAsyncCalls = ArrayDeque<AsyncCall>()
/** 运行的同步调用。 */
private val runningSyncCalls = ArrayDeque<RealCall>()
@Synchronized fun cancelAll() {
for (call in readyAsyncCalls) {
call.call.cancel()
}
for (call in runningAsyncCalls) {
call.call.cancel()
}
for (call in runningSyncCalls) {
call.cancel()
}
}
构造方法内还有一个连接池internal var connectionPool: ConnectionPool = ConnectionPool(),主要作用是管理HTTP和HTTP/2连接的重用以减少网络延迟,实现了多路复用,这也是okhttp的特点之一,目前默认是允许5个空闲连接数
/**一个参数最大空闲连接数,第二个参数保留连接时间,第三个时间单位*/
constructor() : this(5, 5, TimeUnit.MINUTES)
步骤二:构造Request对象
val request = Request.Builder()
.url("请求地址")
.get()//请求方式
.build()
Request内主要是决定了请求地址,请求方式(post,get等),请求头,请求体,比较好理解。只贴关键代码
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>
) {
open class Builder {
internal var url: HttpUrl? = null
internal var method: String
internal var headers: Headers.Builder
internal var body: RequestBody? = null
constructor() {
//默认是“GET”请求
this.method = "GET"
this.headers = Headers.Builder()
}
/**
* 设置URL,如果URL无效时会返回空
*/
open fun url(url: String): Builder {
// Silently replace web socket URLs with HTTP URLs.
val finalUrl: String = when {
url.startsWith("ws:", ignoreCase = true) -> {
"http:${url.substring(3)}"
}
url.startsWith("wss:", ignoreCase = true) -> {
"https:${url.substring(4)}"
}
else -> url
}
return url(finalUrl.toHttpUrl())
/**@JvmStatic
@JvmName("get") fun String.toHttpUrl(): HttpUrl = Builder().parse(null, this).build()*/
}
/**
*设置请求头
*/
open fun header(name: String, value: String) = apply {
headers[name] = value
}
open fun addHeader(name: String, value: String) = apply {
headers.add(name, value)
}
/** 删除请求头 */
open fun removeHeader(name: String) = apply {
headers.removeAll(name)
}
/**
* 设置缓存
*/
open fun cacheControl(cacheControl: CacheControl): Builder {
val value = cacheControl.toString()
return when {
value.isEmpty() -> removeHeader("Cache-Control")
else -> header("Cache-Control", value)
}
}
//各种请求方式
open fun get() = method("GET", null)
open fun post(body: RequestBody) = method("POST", body)
//...
//构建Request
open fun build(): Request {
return Request(
checkNotNull(url) { "url == null" },
method,
headers.build(),
body,
tags.toImmutableMap()
)
}
}
可以看到在构造方法内Okhttp存在默认“GET”请求方式,所以这个可以忽略不写。
步骤三:通过OkHttpClient和Request构造Call对象
val call = mOk.newCall(request)
/** Prepares the [request] to be executed at some point in the future. */
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
通过上面两段代码看到,okhttp的整个网络请求处理都是通过RealCall来进行的,是OkHttp应用程序和网络层之间的桥梁。看RealCall的关键代码
class RealCall(
val client: OkHttpClient,
/** The application's original request unadulterated by redirects or auth headers. */
val originalRequest: Request,
val forWebSocket: Boolean
) : Call {
//连接池
private val connectionPool: RealConnectionPool = client.connectionPool.delegate
//监听http通信
private val eventListener: EventListener = client.eventListenerFactory.create(this)
//超时
private val timeout = object : AsyncTimeout() {
override fun timedOut() {
cancel()
}
}.apply {
timeout(client.callTimeoutMillis.toLong(), MILLISECONDS)
}
//同步请求
override fun execute(): Response {
synchronized(this) {
check(!executed) { "Already Executed" }
executed = true
}
timeout.enter()
callStart()
try {
client.dispatcher.executed(this)
return getResponseWithInterceptorChain()
} finally {
client.dispatcher.finished(this)
}
}
//异步请求
override fun enqueue(responseCallback: Callback) {
synchronized(this) {
check(!executed) { "Already Executed" }
executed = true
}
callStart()
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
//完整的拦截器堆栈
@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
)
//...
拦截链的调用
val response = chain.proceed(originalRequest)
//...
}
RealCall类中对网络的连接、请求、响应进行了处理,并且建立了完整的拦截器链是重要组成部分,拦截链的调用
/**
*承载整个拦截器链的具体拦截器链:所有应用程序
*拦截器、OkHttp核心、所有网络拦截器,最后是网络调用者。
*/
@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"
}
}
// 调用链中的下一个拦截器
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
}
这块儿代码说明了拦截器的调用是根据添加到 interceptors 集合的顺序,逐个往下调用拦截器(关于各个拦截器的具体作用,嗯~ o( ̄▽ ̄)o,随后再说)
最后一步发起请求
发动网络请求会调RealCall类中的同步 execute() or异步方法 enqueue(responseCallback: Callback) 也就是
call.enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
Log.e(TAG, "请求成功")
}
override fun onFailure(call: Call, e: IOException) {
Log.e(TAG, "请求失败")
}
})
至此,最简单的okhttp网络请求流程结束