• Kotlin 中 OkHttp 使用及解析


    build.gradle

    1. dependencies {
    2. //OkHttp
    3. implementation 'com.squareup.okhttp3:okhttp:4.9.0'
    4. }

    简单使用例子

    1. val okHttpClient = OkHttpClient.Builder()
    2. .connectTimeout(Duration.ofSeconds(10))
    3. .readTimeout(Duration.ofSeconds(10))
    4. .writeTimeout(Duration.ofSeconds(10))
    5. .retryOnConnectionFailure(true)
    6. .build()
    7. val request = Request.Builder().url(url).build()
    8. val call = okHttpClient.newCall(request)
    9. call.enqueue(object : Callback {
    10. override fun onFailure(call: Call, e: IOException) {
    11. Log.e("TAG", "onFailure:${e.message}")
    12. }
    13. override fun onResponse(call: Call, response: Response) {
    14. Log.d("TAG", "onResponse: ${response.body?.string()}")
    15. }
    16. })

    1、通过 Builder 模式得到  okHttpClient ,OkHttpClient 包含了对网络请求的全局配置信息,包括链接超时时间、读写超时时间、链接失败重试等配置。

    2、通过 Builder 模式得到 request ,Request 包含了本次网络请求的所有请求参数,包括 url、method、headers、body 等。

    3、通过 newCall 方法得到 call,Call 就是用于发起请求,可用于执行 同步请求(execute)、异步请求(enqueue)、取消请求(cancel)等各种操作。

    4、调用 enqueue 方法发起异步请求返回 response ,Response 就包含了此次网络请求的所有返回信息。

    5、拿到 Response 对象的 body 并以字符串流的方式进行读取。

    一、OkHttpClient

    OkHttpClient 使用 Builder模式来完成初始化,其提供了很多配置参数,每个选项都有默认值。

    1. class Builder constructor() {
    2. internal var dispatcher: Dispatcher = Dispatcher()
    3. internal var connectionPool: ConnectionPool = ConnectionPool()
    4. internal val interceptors: MutableList = mutableListOf()
    5. internal val networkInterceptors: MutableList = mutableListOf()
    6. internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
    7. internal var retryOnConnectionFailure = true
    8. internal var authenticator: Authenticator = Authenticator.NONE
    9. internal var followRedirects = true
    10. internal var followSslRedirects = true
    11. internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
    12. internal var cache: Cache? = null
    13. internal var dns: Dns = Dns.SYSTEM
    14. internal var proxy: Proxy? = null
    15. internal var proxySelector: ProxySelector? = null
    16. internal var proxyAuthenticator: Authenticator = Authenticator.NONE
    17. internal var socketFactory: SocketFactory = SocketFactory.getDefault()
    18. internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
    19. internal var x509TrustManagerOrNull: X509TrustManager? = null
    20. internal var connectionSpecs: List = DEFAULT_CONNECTION_SPECS
    21. internal var protocols: List = DEFAULT_PROTOCOLS
    22. internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
    23. internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
    24. internal var certificateChainCleaner: CertificateChainCleaner? = null
    25. internal var callTimeout = 0
    26. internal var connectTimeout = 10_000
    27. internal var readTimeout = 10_000
    28. internal var writeTimeout = 10_000
    29. internal var pingInterval = 0
    30. internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE
    31. internal var routeDatabase: RouteDatabase? = null
    32. }

    二、Request 

    Request 包含了网络请求时的所有请求参数,一共包含以下五个。

    1. open class Builder {
    2. internal var url: HttpUrl? = null
    3. internal var method: String
    4. internal var headers: Headers.Builder
    5. internal var body: RequestBody? = null
    6. /** A mutable map of tags, or an immutable empty map if we don't have any. */
    7. internal var tags: MutableMap, Any> = mutableMapOf()
    8. }

    三、Call 

    当调用 okHttpClient.newCall(request)   时就会得到一个 call 对象。

    1. /** Prepares the [request] to be executed at some point in the future. */
    2. override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

     call 是一个接口,我们可以将其看做是网络请求的启动器,可用于同步请求异步请求,但重复发起多次请求的话会抛出异常。

    1. interface Call : Cloneable {
    2. /** Returns the original request that initiated this call. */
    3. fun request(): Request
    4. /**
    5. * Invokes the request immediately, and blocks until the response can be processed or is in error.
    6. *
    7. * To avoid leaking resources callers should close the [Response] which in turn will close the
    8. * underlying [ResponseBody].
    9. *
    10. * ```
    11. * // ensure the response (and underlying response body) is closed
    12. * try (Response response = client.newCall(request).execute()) {
    13. * ...
    14. * }
    15. * ```
    16. *
    17. * The caller may read the response body with the response's [Response.body] method. To avoid
    18. * leaking resources callers must [close the response body][ResponseBody] or the response.
    19. *
    20. * Note that transport-layer success (receiving a HTTP response code, headers and body) does not
    21. * necessarily indicate application-layer success: `response` may still indicate an unhappy HTTP
    22. * response code like 404 or 500.
    23. *
    24. * @throws IOException if the request could not be executed due to cancellation, a connectivity
    25. * problem or timeout. Because networks can fail during an exchange, it is possible that the
    26. * remote server accepted the request before the failure.
    27. * @throws IllegalStateException when the call has already been executed.
    28. */
    29. @Throws(IOException::class)
    30. fun execute(): Response
    31. /**
    32. * Schedules the request to be executed at some point in the future.
    33. *
    34. * The [dispatcher][OkHttpClient.dispatcher] defines when the request will run: usually
    35. * immediately unless there are several other requests currently being executed.
    36. *
    37. * This client will later call back `responseCallback` with either an HTTP response or a failure
    38. * exception.
    39. *
    40. * @throws IllegalStateException when the call has already been executed.
    41. */
    42. fun enqueue(responseCallback: Callback)
    43. /** Cancels the request, if possible. Requests that are already complete cannot be canceled. */
    44. fun cancel()
    45. /**
    46. * Returns true if this call has been either [executed][execute] or [enqueued][enqueue]. It is an
    47. * error to execute a call more than once.
    48. */
    49. fun isExecuted(): Boolean
    50. fun isCanceled(): Boolean
    51. /**
    52. * Returns a timeout that spans the entire call: resolving DNS, connecting, writing the request
    53. * body, server processing, and reading the response body. If the call requires redirects or
    54. * retries all must complete within one timeout period.
    55. *
    56. * Configure the client's default timeout with [OkHttpClient.Builder.callTimeout].
    57. */
    58. fun timeout(): Timeout
    59. /**
    60. * Create a new, identical call to this one which can be enqueued or executed even if this call
    61. * has already been.
    62. */
    63. public override fun clone(): Call
    64. fun interface Factory {
    65. fun newCall(request: Request): Call
    66. }
    67. }

     ReallCall 是 Call 接口的唯一实现类

    当调用 execute 方法发起同步请求时,

    1、判断是否重复请求。

    2、时间记录。

    3、将自身加入到 dispatcher 中,并在请求结束时从 dispatcher 中移除自身。

    4、通过 getResponseWithInterceptorChain 方法得到  response 对象。

    1. override fun execute(): Response {
    2. check(executed.compareAndSet(false, true)) { "Already Executed" }
    3. timeout.enter()
    4. callStart()
    5. try {
    6. client.dispatcher.executed(this)
    7. return getResponseWithInterceptorChain()
    8. } finally {
    9. client.dispatcher.finished(this)
    10. }
    11. }

    四、Dispatcher 

    Dispatcher 是一个调度器,用于对全局的网络请求进行缓存调度,其包含一下几个成员变量。

    1. var maxRequests = 64
    2. var maxRequestsPerHost = 5
    3. /** Ready async calls in the order they'll be run. */
    4. private val readyAsyncCalls = ArrayDeque()
    5. /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
    6. private val runningAsyncCalls = ArrayDeque()
    7. /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
    8. private val runningSyncCalls = ArrayDeque()

    1、maxRequests  同一时间允许并发执行网络请求的最大线程数。

    2、maxRequestsPerHost  同一个 host 下的最大同时请求数。

    3、readyAsyncCalls  保存当前等待执行的异步任务

    4、runningAsyncCalls  保存当前正在执行的异步任务。

    5、runningSyncCalls  保存等钱正在执行的同步任务。 

    五、getResponseWithInterceptorChain

    其主要逻辑就是通过拦截器来完成整个网络请求过程。

    1. @Throws(IOException::class)
    2. internal fun getResponseWithInterceptorChain(): Response {
    3. // Build a full stack of interceptors.
    4. val interceptors = mutableListOf()
    5. interceptors += client.interceptors
    6. interceptors += RetryAndFollowUpInterceptor(client)
    7. interceptors += BridgeInterceptor(client.cookieJar)
    8. interceptors += CacheInterceptor(client.cache)
    9. interceptors += ConnectInterceptor
    10. if (!forWebSocket) {
    11. interceptors += client.networkInterceptors
    12. }
    13. interceptors += CallServerInterceptor(forWebSocket)
    14. val chain = RealInterceptorChain(
    15. call = this,
    16. interceptors = interceptors,
    17. index = 0,
    18. exchange = null,
    19. request = originalRequest,
    20. connectTimeoutMillis = client.connectTimeoutMillis,
    21. readTimeoutMillis = client.readTimeoutMillis,
    22. writeTimeoutMillis = client.writeTimeoutMillis
    23. )
    24. var calledNoMoreExchanges = false
    25. try {
    26. val response = chain.proceed(originalRequest)
    27. if (isCanceled()) {
    28. response.closeQuietly()
    29. throw IOException("Canceled")
    30. }
    31. return response
    32. } catch (e: IOException) {
    33. calledNoMoreExchanges = true
    34. throw noMoreExchanges(e) as Throwable
    35. } finally {
    36. if (!calledNoMoreExchanges) {
    37. noMoreExchanges(null)
    38. }
    39. }
    40. }

    六、interceptor 

    interceptor 多个拦截器增加串行调用逻辑

    1. package com.gxx
    2. class Request
    3. class Response
    4. interface Chain {
    5. fun request(): Request
    6. fun proceed(request: Request): Response
    7. }
    8. interface Interceptor {
    9. fun intercept(chain: Chain): Response
    10. }
    11. class RealInterceptorChain(
    12. private val request: Request,
    13. private val interceptors: List,
    14. private val index: Int
    15. ) : Chain {
    16. private fun copy(index: Int): RealInterceptorChain {
    17. return RealInterceptorChain(request, interceptors, index)
    18. }
    19. override fun request(): Request {
    20. return request
    21. }
    22. override fun proceed(request: Request): Response {
    23. val next = copy(index + 1)
    24. val interceptor = interceptors[index]
    25. return interceptor.intercept(next)
    26. }
    27. }
    28. class LogInterceptor : Interceptor {
    29. override fun intercept(chain: Chain): Response {
    30. val request = chain.request()
    31. println("LogInterceptor -- getRequest")
    32. val response = chain.proceed(request)
    33. println("LogInterceptor ---- getResponse")
    34. return response
    35. }
    36. }
    37. class HeaderInterceptor : Interceptor {
    38. override fun intercept(chain: Chain): Response {
    39. val request = chain.request()
    40. println("HeaderInterceptor -- getRequest")
    41. val response = chain.proceed(request)
    42. println("HeaderInterceptor ---- getResponse")
    43. return response
    44. }
    45. }
    46. class CallServerInterceptor : Interceptor {
    47. override fun intercept(chain: Chain): Response {
    48. val request = chain.request()
    49. println("CallServerInterceptor -- getRequest")
    50. val response = Response()
    51. println("CallServerInterceptor ---- getResponse")
    52. return response
    53. }
    54. }
    55. fun main() {
    56. val interceptorList = mutableListOf()
    57. interceptorList.add(LogInterceptor())
    58. interceptorList.add(HeaderInterceptor())
    59. interceptorList.add(CallServerInterceptor())
    60. val request = Request()
    61. val realInterceptorChain = RealInterceptorChain(request, interceptorList, 0)
    62. val response = realInterceptorChain.proceed(request)
    63. println("main response")
    64. }
    65. /*
    66. fun main() {
    67. val interceptorList = mutableListOf()
    68. interceptorList.add(LogInterceptor())
    69. interceptorList.add(HeaderInterceptor())
    70. val request = Request()
    71. val realInterceptorChain = RealInterceptorChain(request, interceptorList, 0)
    72. val response = realInterceptorChain.proceed(request)
    73. println("main response")
    74. }*/

    参考:

    https://github.com/leavesCZY/AndroidGuide/blob/master/%E4%B8%BB%E6%B5%81%E5%BC%80%E6%BA%90%E5%BA%93%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%EF%BC%8811%EF%BC%89OkHttp%20%E6%BA%90%E7%A0%81%E8%AF%A6%E8%A7%A3.md

  • 相关阅读:
    Python-IO编程和异常
    2. 在STM32CubeMX建立的Keil5工程中添加自定义的相关文件
    数据安全能力建设框架
    .Net依赖注入神器Scrutor(下)
    各种 sql 语句
    机器学习-特征选择:如何使用互信息特征选择挑选出最佳特征?
    其他数据库小知识
    如何使用show profile 查看sql的执行周期
    时间很快,我已二十
    【Linux】VSCode连接远程Linux服务器
  • 原文地址:https://blog.csdn.net/u010498248/article/details/132582022