Android开源库——OkHttp

本文介绍了OkHttp,Square出品的Android网络库,演示了如何添加依赖、创建请求、执行并解析响应,以及提供OkHttp最佳用法,包括通过OkHttpUtil封装并发请求处理。

OkHttp是什么?

用于简化Android网络编程的开源框架

推荐前提阅读:Android基础——网络编程

OkHttp使用

依赖

implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.14'

权限

<uses-permission android:name="android.permission.INTERNET" />

get

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/send_request"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="send_request" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/response_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </ScrollView>

</LinearLayout>

修改MainAcitivity:

  • 创建OkHttpClient
  • 创建Request添加相关参数(网址、响应时间)传入OkHttpClient的newCall()方法中,并调用enqueue()添加回调方法
  • 调用Response的body()和string()方法获取字符串
public class MainActivity extends AppCompatActivity {

    private TextView responseText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        responseText = findViewById(R.id.response_text);
        Button sendRequest = findViewById(R.id.send_request);
        sendRequest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendRequestWithOkHttp();
            }
        });
    }

    private void sendRequestWithOkHttp() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                sendOkHttpRequest("https://www.baidu.com", new Callback() {
                    @Override
                    public void onFailure(@NonNull Call call, @NonNull IOException e) {
                        e.printStackTrace();
                    }

                    @Override
                    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                        showResponse(response.body().string());
                    }
                });

            }
        }).start();
    }

    public void sendOkHttpRequest(String address, okhttp3.Callback callback) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(address)
                .build();
        client.newCall(request).enqueue(callback);
    }
    
    private void showResponse(final String toString) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                responseText.setText(toString);
            }
        });
    }
}

post

使用post需创建RequestBody对象并传入到Request的post()方法:

RequestBody requestBody=new FormBody.Builder()
        .add("username","admin")
        .add("password","123456")
        .build();
Request request = new Request.Builder()
        .url("https://www.baidu.com")
        .post(requestBody)
        .build();

OkHttp源码解析

Call

Call中Factory的newCall()接收一个Request,并返回Call

  • execute() 同步调用,会阻塞直到Response返回或出错
  • enqueue() 异步调用,需要传入回调
interface Call : Cloneable {
  fun request(): Request

  @Throws(IOException::class)
  fun execute(): Response

  fun enqueue(responseCallback: Callback)

  fun isExecuted(): Boolean

  fun isCanceled(): Boolean

  fun timeout(): Timeout

  public override fun clone(): Call

  fun interface Factory {
    fun newCall(request: Request): Call
  }
}

Callback

异步调用回调通知

  • 失败时的参数为当前Call和异常
  • 成功时的参数为当前Call和Response
interface Callback {

  fun onFailure(
    call: Call,
    e: IOException,
  )
  
  @Throws(IOException::class)
  fun onResponse(
    call: Call,
    response: Response,
  )
}

Request

通过Build设置url、header等

class Request internal constructor(builder: Builder) {
  ......
  constructor(
    url: HttpUrl,
    headers: Headers = headersOf(),
    body: RequestBody? = null,
  ) : this(
    Builder()
      .url(url)
      .headers(headers)
      .method(
        when {
          method != "\u0000" -> method
          body != null -> "POST"
          else -> "GET"
        },
        body,
      ),
  )
  
  ......

  fun newBuilder(): Builder = Builder(this)

  ......

  open class Builder {
    internal var url: HttpUrl? = null
    internal var method: String
    internal var headers: Headers.Builder
    internal var body: RequestBody? = null
    internal var cacheUrlOverride: HttpUrl? = null

    constructor() {
      this.method = "GET"
      this.headers = Headers.Builder()
    }

    internal constructor(request: Request) {
      this.url = request.url
      this.method = request.method
      this.body = request.body
      this.tags =
        when {
          request.tags.isEmpty() -> mapOf()
          else -> request.tags.toMutableMap()
        }
      this.headers = request.headers.newBuilder()
      this.cacheUrlOverride = request.cacheUrlOverride
    }

    open fun url(url: HttpUrl): Builder =
      apply {
        this.url = url
      }

    open fun url(url: String): Builder {
      return url(canonicalUrl(url).toHttpUrl())
    }

    open fun url(url: URL) = url(url.toString().toHttpUrl())

    open fun header(
      name: String,
      value: String,
    ) = commonHeader(name, value)

    open fun addHeader(
      name: String,
      value: String,
    ) = commonAddHeader(name, value)
    
	......
	
    open fun build(): Request = Request(this)
  }
}

Response

通过Build设置code、body等

class Response internal constructor(.....) : Closeable {

  open class Builder {
    internal var request: Request? = null
    internal var protocol: Protocol? = null
    internal var code = -1
    internal var message: String? = null
    internal var handshake: Handshake? = null
    internal var headers: Headers.Builder
    internal var body: ResponseBody = commonEmptyResponse
    internal var networkResponse: Response? = null
    internal var cacheResponse: Response? = null
    internal var priorResponse: Response? = null
    internal var sentRequestAtMillis: Long = 0
    internal var receivedResponseAtMillis: Long = 0
    internal var exchange: Exchange? = null
    internal var trailersFn: (() -> Headers) = { Headers.headersOf() }

    constructor() {
      headers = Headers.Builder()
    }

    internal constructor(response: Response) {
      this.request = response.request
      this.protocol = response.protocol
      this.code = response.code
      this.message = response.message
      this.handshake = response.handshake
      this.headers = response.headers.newBuilder()
      this.body = response.body
      this.networkResponse = response.networkResponse
      this.cacheResponse = response.cacheResponse
      this.priorResponse = response.priorResponse
      this.sentRequestAtMillis = response.sentRequestAtMillis
      this.receivedResponseAtMillis = response.receivedResponseAtMillis
      this.exchange = response.exchange
      this.trailersFn = response.trailersFn
    }

    open fun request(request: Request) = commonRequest(request)

    open fun protocol(protocol: Protocol) = commonProtocol(protocol)

    open fun code(code: Int) = commonCode(code)

    open fun message(message: String) = commonMessage(message)

    open fun header(
      name: String,
      value: String,
    ) = commonHeader(name, value)


    open fun addHeader(
      name: String,
      value: String,
    ) = commonAddHeader(name, value)

    open fun headers(headers: Headers) = commonHeaders(headers)

    open fun body(body: ResponseBody) = commonBody(body)


    open fun build(): Response {
      check(code >= 0) { "code < 0: $code" }
      return Response(
        checkNotNull(request) { "request == null" },
        checkNotNull(protocol) { "protocol == null" },
        checkNotNull(message) { "message == null" },
        code,
        handshake,
        headers.build(),
        body,
        networkResponse,
        cacheResponse,
        priorResponse,
        sentRequestAtMillis,
        receivedResponseAtMillis,
        exchange,
        trailersFn,
      )
    }
  }
}

OkHttpClient

  • 继承Call.Factory重写newCall()
  • 继承WebSocket.Factory重写newWebSocket()
open class OkHttpClient internal constructor(
  builder: Builder,
) : Call.Factory, WebSocket.Factory {
	......
}

构造函数传入默认的Builder,内部创建Dispatcher、connectionPool等

constructor() : this(Builder())

class Builder() {
    internal var dispatcher: Dispatcher = Dispatcher()
    internal var connectionPool: ConnectionPool? = null
    internal val interceptors: MutableList<Interceptor> = mutableListOf()
    internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
    internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
    internal var retryOnConnectionFailure = true
    internal var fastFallback = true
    internal var authenticator: Authenticator = Authenticator.NONE
    internal var followRedirects = true
    internal var followSslRedirects = true
    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 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 webSocketCloseTimeout = RealWebSocket.CANCEL_AFTER_CLOSE_MILLIS.toInt()
    internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE
    internal var routeDatabase: RouteDatabase? = null
    internal var taskRunner: TaskRunner? = null
	......
}

newCall()返回RealCall对象

override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

RealCall

RealCall是Call的实现类,重写了

  • execute()调用dispatcher的executed()和finished(),调用getResponseWithInterceptorChain()
  • enqueue()将Callback封装成AsyncCall调用dispatcher的enqueue()
class RealCall(
  val client: OkHttpClient,
  val originalRequest: Request,
  val forWebSocket: Boolean,
) : Call, Cloneable {
  private val connectionPool: RealConnectionPool = client.connectionPool.delegate

  internal val eventListener: EventListener = client.eventListenerFactory.create(this)

  private val timeout =
    object : AsyncTimeout() {
      override fun timedOut() {
        this@RealCall.cancel()
      }
    }.apply {
      timeout(client.callTimeoutMillis.toLong(), MILLISECONDS)
    }

  private val executed = AtomicBoolean()

  @Volatile private var canceled = false

  override fun timeout(): Timeout = timeout

  override fun request(): Request = originalRequest

  override fun cancel() {
    if (canceled) return // Already canceled.

    canceled = true
    exchange?.cancel()
    for (plan in plansToCancel) {
      plan.cancel()
    }

    eventListener.canceled(this)
  }

  override fun isCanceled(): Boolean = canceled

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

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

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

	override fun isExecuted(): Boolean = executed.get()

	private fun callStart() {
  		this.callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()")
 	 	eventListener.callStart(this)
	}	
	.....
}

AsyncCall

继承Runnable,run()中调用getResponseWithInterceptorChain(),回调onResponse()和onFailure()

  inner class AsyncCall(
    private val responseCallback: Callback,
  ) : Runnable {
    @Volatile var callsPerHost = AtomicInteger(0)
      private set

    fun reuseCallsPerHostFrom(other: AsyncCall) {
      this.callsPerHost = other.callsPerHost
    }

    val host: String
      get() = originalRequest.url.host

    val request: Request
      get() = originalRequest

    val call: RealCall
      get() = this@RealCall

    /**
     * Attempt to enqueue this async call on [executorService]. This will attempt to clean up
     * if the executor has been shut down by reporting the call as failed.
     */
    fun executeOn(executorService: ExecutorService) {
      client.dispatcher.assertThreadDoesntHoldLock()

      var success = false
      try {
        executorService.execute(this)
        success = true
      } catch (e: RejectedExecutionException) {
        failRejected(e)
      } finally {
        if (!success) {
          client.dispatcher.finished(this) // This call is no longer running!
        }
      }
    }

    internal fun failRejected(e: RejectedExecutionException? = null) {
      val ioException = InterruptedIOException("executor rejected")
      ioException.initCause(e)
      noMoreExchanges(ioException)
      responseCallback.onFailure(this@RealCall, ioException)
    }

    override fun run() {
      threadName("OkHttp ${redactedUrl()}") {
        var signalledCallback = false
        timeout.enter()
        try {
          val response = getResponseWithInterceptorChain()
          signalledCallback = true
          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 {
            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 {
          client.dispatcher.finished(this)
        }
      }
    }
  }

Dispatcher

executed()

将RealCall添加到同步队列runningSyncCalls

  @Synchronized internal fun executed(call: RealCall) {
    runningSyncCalls.add(call)
  }

enqueue()

将AsyncCall添加到同步队列readyAsyncCalls,根据host判断队列中是否已经存在,调用promoteAndExecute()

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

  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 promoteAndExecute(): Boolean {
    this.assertThreadDoesntHoldLock()

    val executableCalls = mutableListOf<AsyncCall>()
    val isRunning: Boolean
    synchronized(this) {
      val i = readyAsyncCalls.iterator()
      while (i.hasNext()) {
        val asyncCall = i.next()

        if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
        if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.

        i.remove()
        asyncCall.callsPerHost.incrementAndGet()
        executableCalls.add(asyncCall)
        runningAsyncCalls.add(asyncCall)
      }
      isRunning = runningCallsCount() > 0
    }

    if (executorService.isShutdown) {
      for (i in 0 until executableCalls.size) {
        val asyncCall = executableCalls[i]
        asyncCall.callsPerHost.decrementAndGet()

        synchronized(this) {
          runningAsyncCalls.remove(asyncCall)
        }

        asyncCall.failRejected()
      }
      idleCallback?.run()
    } else {
      for (i in 0 until executableCalls.size) {
        val asyncCall = executableCalls[i]
        asyncCall.executeOn(executorService)
      }
    }

    return isRunning
  }

promoteAndExecute()从readyAsyncCalls取出asyncCall添加到runningAsyncCalls,然后判断线程池状态,若已关闭则调用failRejected(),否则调用executeOn()交给线程池(SynchronousQueue可直接将任务从生产者移交给工作者线程)

finish()

从runningSyncCalls移除已执行完的RealCall,调用promoteAndExecute()执行下一个

  internal fun finished(call: RealCall) {
    finished(runningSyncCalls, call)
  }

  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()
    }
  }

getResponseWithInterceptorChain()

不管同步还是异步都会调用RealCall中的getResponseWithInterceptorChain()获取数据

  • 创建Interceptor封装到RealInterceptorChain,调用其proceed()方法
  @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)
      }
    }
  }

Interceptor

用于定义拦截规则和构造责任链

fun interface Interceptor {
  @Throws(IOException::class)
  fun intercept(chain: Chain): Response

  companion object {

    inline operator fun invoke(crossinline block: (chain: Chain) -> Response): Interceptor = Interceptor { block(it) }
  }

  interface Chain {
    fun request(): Request

    @Throws(IOException::class)
    fun proceed(request: Request): Response

    fun connection(): Connection?

    fun call(): Call

    fun connectTimeoutMillis(): Int

    fun withConnectTimeout(
      timeout: Int,
      unit: TimeUnit,
    ): Chain

    fun readTimeoutMillis(): Int

    fun withReadTimeout(
      timeout: Int,
      unit: TimeUnit,
    ): Chain

    fun writeTimeoutMillis(): Int

    fun withWriteTimeout(
      timeout: Int,
      unit: TimeUnit,
    ): Chain
  }
}

RealInterceptorChain

  • proceed()调用Interceptor子类的intercept()
  • 子类的intercept()又会调用下一个Interceptor的proceed()
  • 即每个Interceptor子类中在proceed()之前的为拦截代码,在其后的为返回代码
class RealInterceptorChain(
  internal val call: RealCall,
  private val interceptors: List<Interceptor>,
  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 {
  private var calls: Int = 0

  ......

  @Throws(IOException::class)
  override fun proceed(request: Request): Response {
    check(index < interceptors.size)

    calls++

    ......

    // 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",
      )

    ......

    return response
  }
}

RetryAndFollowUpInterceptor

class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Interceptor {
  @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 newRoutePlanner = true
    var recoveredFailures = listOf<IOException>()
    //通过死循环实现retry或处理下一个request
    while (true) {
      call.enterNetworkInterceptorExchange(request, newRoutePlanner, chain)

      var response: Response
      var closeActiveExchange = true
      try {
        if (call.isCanceled()) {
          throw IOException("Canceled")
        }
		//调用下一个拦截器的proceed()
        try {
          response = realChain.proceed(request)
          newRoutePlanner = true
        } catch (e: IOException) {
		  //若无法恢复则抛出异常,否则通过continue继续尝试
          if (!recover(e, call, request, requestSendStarted = e !is ConnectionShutdownException)) {
            throw e.withSuppressed(recoveredFailures)
          } else {
            recoveredFailures += e
          }
          newRoutePlanner = false
          continue
        }

        //若没有异常则构造response
        response =
          response.newBuilder()
            .request(request)
            .priorResponse(priorResponse?.stripBody())
            .build()

        val exchange = call.interceptorScopedExchange
        val followUp = followUpRequest(response, exchange)
		//若接下来没有Request则返回response
        if (followUp == null) {
          if (exchange != null && exchange.isDuplex) {
            call.timeoutEarlyExit()
          }
          closeActiveExchange = false
          return response
        }

        val followUpBody = followUp.body
        if (followUpBody != null && followUpBody.isOneShot()) {
          closeActiveExchange = false
          return response
        }

        response.body.closeQuietly()

        if (++followUpCount > MAX_FOLLOW_UPS) {
          throw ProtocolException("Too many follow-up requests: $followUpCount")
        }

        request = followUp
        priorResponse = response
      } finally {
        call.exitNetworkInterceptorExchange(closeActiveExchange)
      }
    }
  }
  ......
}

BridgeInterceptor

在这里主要构造request的请求头等信息

class BridgeInterceptor(private val cookieJar: CookieJar) : Interceptor {
  @Throws(IOException::class)
  override fun intercept(chain: Interceptor.Chain): Response {
    val userRequest = chain.request()
    val requestBuilder = userRequest.newBuilder()

    val body = userRequest.body
    if (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 = false
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
      transparentGzip = true
      requestBuilder.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", USER_AGENT)
    }

    val networkRequest = requestBuilder.build()
    val networkResponse = chain.proceed(networkRequest)

    cookieJar.receiveHeaders(networkRequest.url, networkResponse.headers)

    val responseBuilder =
      networkResponse.newBuilder()
        .request(networkRequest)

    if (transparentGzip &&
      "gzip".equals(networkResponse.header("Content-Encoding"), ignoreCase = true) &&
      networkResponse.promisesBody()
    ) {
      val responseBody = networkResponse.body
      if (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()
  }

CacheInterceptor

class CacheInterceptor(internal val cache: Cache?) : Interceptor {
  @Throws(IOException::class)
  override fun intercept(chain: Interceptor.Chain): Response {
    val call = chain.call()
    val cacheCandidate = cache?.get(chain.request().requestForCache())

    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()
    }

    //若没网且缓存为空,则返回504
    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)")
        .sentRequestAtMillis(-1L)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build().also {
          listener.satisfactionFailure(call, it)
        }
    }

    //若没网且缓存不为空,将缓存内容添加到cacheResponse并返回
    if (networkRequest == null) {
      return cacheResponse!!.newBuilder()
        .cacheResponse(cacheResponse.stripBody())
        .build().also {
          listener.cacheHit(call, it)
        }
    }
    
	//上面是没网的情况,下面是有网的情况
    if (cacheResponse != null) {
      listener.cacheConditionalHit(call, cacheResponse)
    } else if (cache != null) {
      listener.cacheMiss(call)
    }
	//执行下一个拦截器
    var networkResponse: Response? = null
    try {
      networkResponse = chain.proceed(networkRequest)
    } finally {
      if (networkResponse == null && cacheCandidate != null) {
        cacheCandidate.body.closeQuietly()
      }
    }

    //当前缓存有空间
    if (cacheResponse != null) {
      if (networkResponse?.code == HTTP_NOT_MODIFIED) {	
      //304,上次请求后,响应的内容未改变,更新cacheResponse和cache并返回
        val response =
          cacheResponse.newBuilder()
            .headers(combine(cacheResponse.headers, networkResponse.headers))
            .sentRequestAtMillis(networkResponse.sentRequestAtMillis)
            .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis)
            .cacheResponse(cacheResponse.stripBody())
            .networkResponse(networkResponse.stripBody())
            .build()

        networkResponse.body.close()

        cache!!.trackConditionalCacheHit()
        cache.update(cacheResponse, response)
        return response.also {
          listener.cacheHit(call, it)
        }
      } else {
        cacheResponse.body.closeQuietly()
      }
    }
	//根据cacheResponse和networkResponse构造新的response并返回
    val response =
      networkResponse!!.newBuilder()
        .cacheResponse(cacheResponse?.stripBody())
        .networkResponse(networkResponse.stripBody())
        .build()
        
	//写入用户设置的缓存
    if (cache != null) {
      val cacheNetworkRequest = networkRequest.requestForCache()

      if (response.promisesBody() && CacheStrategy.isCacheable(response, cacheNetworkRequest)) {
        // Offer this request to the cache.
        val cacheRequest = cache.put(response.newBuilder().request(cacheNetworkRequest).build())
        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.
        }
      }
    }

    return response
  }
  ......
}

ConnectInterceptor

初始化Exchange

object ConnectInterceptor : Interceptor {
  @Throws(IOException::class)
  override fun intercept(chain: Interceptor.Chain): Response {
    val realChain = chain as RealInterceptorChain
    val exchange = realChain.call.initExchange(realChain)
    val connectedChain = realChain.copy(exchange = exchange)
    return connectedChain.proceed(realChain.request)
  }
}

CallServerInterceptor

通过exchange向服务器发起网络请求,并读取结果

class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor {
  @Throws(IOException::class)
  override fun intercept(chain: Interceptor.Chain): Response {
    val realChain = chain as RealInterceptorChain
    val exchange = realChain.exchange!!
    val request = realChain.request
    val requestBody = request.body
    val sentRequestMillis = System.currentTimeMillis()

    var invokeStartEvent = true
    var responseBuilder: Response.Builder? = null
    var sendRequestException: IOException? = null
    try {
      exchange.writeRequestHeaders(request)

      if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
        // If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
        // Continue" response before transmitting the request body. If we don't get that, return
        // what we did get (such as a 4xx response) without ever transmitting the request body.
        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()) {
            // 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 {
      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.code

      if (shouldIgnoreAndWaitForRealResponse(code, exchange)) {
        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) {
          // Connection is upgrading, but we need to ensure interceptors see a non-null response body.
          response.stripBody()
        } 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() > 0L) {
        throw ProtocolException(
          "HTTP $code had non-zero Content-Length: ${response.body.contentLength()}",
        )
      }
      return response
    } catch (e: IOException) {
      if (sendRequestException != null) {
        sendRequestException.addSuppressed(e)
        throw sendRequestException
      }
      throw e
    }
  }
  .....
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值