略解Okhttp

使用

val okHttpClient = OkHttpClient()
        val request = Request.Builder().url("www.baidu.com").build()
        val response = okHttpClient.newCall(request).execute()
        response.body?.string()
...

流程

  1. 创建OkHttpClient对象
  2. 创建Request对象
  3. 同步/异步请求

创建OkHttpClient对象

创建Request对象

Request对象的创建由建造者完成,默认的方法是GET,headers为空。

接着调用url方法,url方法作用是把url转换成http:..或https:…形式的字符串,用字符串创建HttpUrl对象。HttpUrl对象是把Url里的域名、端口、位置(#ToASCII)等信息以每个变量的形式单独存储。再然后用上边的值作为属性,创建Request对象。Request对象与HttpUrl相比多了body、method、headers这些值。

Request与HttpUrl的作用相似,作为请求的一部分。只不过包含了更多了请求信息。

创建RealCall对象

源码中对RealCall类的介绍:

/**
 * Bridge between OkHttp's application and network layers. This class exposes high-level application
 * layer primitives: connections, requests, responses, and streams.
 *
 * This class supports [asynchronous canceling][cancel]. This is intended to have the smallest
 * blast radius possible. If an HTTP/2 stream is active, canceling will cancel that stream but not
 * the other streams sharing its connection. But if the TLS handshake is still in progress then
 * canceling may break the entire connection.
 */

RealCall才是真正用来请求的类。

其中execute()为同步请求的方法入口,enqueue()为异步请求的方法入口。

execute()方法:

源码:

override fun execute(): Response {
check(executed.compareAndSet(false, true)){"Already Executed"}

timeout.enter()
  callStart()
  try {
    client.dispatcher.executed(this)
    return getResponseWithInterceptorChain()
  } finally {
    client.dispatcher.finished(this)
  }
}

client.dispatcher.executed(this)里。

/** Used by [Call.execute] to signal it is in-flight. */
  @Synchronized internal fun executed(call: RealCall) {
    runningSyncCalls.add(call)
  }

再看

/** Ready async calls in the order they'll be run. */
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. */
private val runningSyncCalls = ArrayDeque<RealCall>()

上边只是把当前的Call放到Liist队列中,RealCallexecute()的方法需要返回值,真正的执行肯定是getResponseWithInterceptorChain()

@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(..)方法的结果。

@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
}

请求时能不断调用下一个拦截器是因为在拦截器里不拦截时,又调用到RealInterceptorChain的proceed(..)里。而

// Call the next interceptor in the chain.
val next = copy(index = index + 1, request = request)
val interceptor = interceptors[index]

copy(..)里传入是的index+1,相当于每调用一次,index+1。

最后在RealCall修改状态:

private fun <T> finished(calls: Deque<T>, call: T) {
  val idleCallback: Runnable?
synchronized(this){
if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!")
    idleCallback = this.idleCallback
}

val isRunning = promoteAndExecute()

  if (!isRunning && idleCallback != null) {
    idleCallback.run()
  }
}

异步执行与同步前部分相似

异步的入口是enqueue()。源码:

override fun enqueue(responseCallback: Callback) {
check(executed.compareAndSet(false, true)){"Already Executed"}

callStart()
  client.dispatcher.enqueue(AsyncCall(responseCallback))
}

AsyncCall是RealCall的内部类,实现了Runnable接口。持有外部类的引用,在调用

拦截器

Interceptor作用
RetryAndFollowUpInterceptor重试、重定向
BridgeInterceptor添加header,包括压缩格式、cookie、Content-Type
CacheInterceptor判断是否可以用缓存过的响应
ConnectInterceptor建立连接,找不到时创建Socket、DNS、TCP握手
CallServerInterceptor用okio传输header和body