okhttp源码系列-执行一次网络请求

带着目的阅读源码,okhttp如何执行一次网络请求呢?

本文通过samples.guide模块中的GetExample作为切入口。

入口

GetExample代码如下

kotlin 复制代码
class GetExample {

  val client: OkHttpClient = OkHttpClient() // 创建okhttp客户端

  fun run(url: String): String? {
    val request: Request = Request.Builder() // 创建请求
        .url(url)
        .addHeader("User-Agent", "OkHttp Example")
        .build() // 通过链式+build模式创建一个网络请求
    return runCatching {
      client.newCall(request).execute().use { response -> // 同步获取网络响应
        if (!response.isSuccessful) {
          null
        } else {
          response.body?.string()
        }
      } 
    }.getOrNull()
  }
}

从上述代码可知执行一次网络请求需要如下步骤:

  • step 1:创建okhttp客户端client
kotlin 复制代码
val client: OkHttpClient = OkHttpClient() // 创建okhttp客户端
  • step 2:创建网络请求并配置必要参数
kotlin 复制代码
val request: Request = Request.Builder() // 创建请求
    .url(url)
    .addHeader("User-Agent", "OkHttp Example")
    .build() // 通过链式+build模式创建一个网络请求
  • step 3:执行网络请求并获取网络返回
kotlin 复制代码
return runCatching {
  client.newCall(request).execute().use { response -> // 同步获取网络响应
    if (!response.isSuccessful) {
      null
    } else {
      response.body?.string()
    }
  }
}.getOrNull()

看上去是不是很简单,复杂的网络请求只需要三步即可完成,接下来我们带着问题逐步分析。

什么是okhttp客户端

OkHttp用途

第一步中创建了OkHttpClient对象,注释中对其的定义为:

Factory for calls, which can be used to send HTTP requests and read their responses.

用于生成Call的工厂,Call可以发送并接收HTTP请求。Call是一个接口,代表一个可以执行的HTTP请求,如下:

kotlin 复制代码
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
  }
}

OkHttp的声明如下,除了可生成Call之外,还可生成一个WebSocket对象。

kotlin 复制代码
open class OkHttpClient internal constructor(
  builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory

WebSocket是一个WebSocket协议的操作接口,可利用它发送基于WebSocket协议的消息,WebSocket协议是基于TCP协议的可全双工通信的应用层网络协议,WebSocket接口如下:

kotlin 复制代码
interface WebSocket {
  fun request(): Request

  fun queueSize(): Long

  fun send(text: String): Boolean

  fun send(bytes: ByteString): Boolean

  fun close(code: Int, reason: String?): Boolean

  fun cancel()

  fun interface Factory {
    fun newWebSocket(request: Request, listener: WebSocketListener): WebSocket
  }
}

总结一下:OkHttpClient主要用途是生成Call对象(处理HTTP请求),生成WebSocket对象(处理WebSocket请求)

OkHttpClient属性

OkHttpClient基于Builder建造者模式,可通过链式结构清晰地设置网络配置,具体的配置项及其相应功能如下:

属性 功能
dispatcher 调度器,设置执行异步请求的策略。
connectionPool 设置可回收复用的HTTP/HTTPS的连接池,相同地址的HTTP请求可共享一个连接。
interceptors 一个可修改的拦截器列表,该列表作用于建立连接之前到选择响应源的区间。
networkInterceptors 一个可修改的网络拦截器列表,该列表作用于单个请求发起到响应的区间。
eventListenerFactory 可监听到该客户端网络调用中各个阶段的情况
retryOnConnectionFailure 设置此客户端在遇到连接问题时是否重试,默认为true,在一些特定情况下重试
authenticator 当网络返回出现授权问题时,设置授权并重试。
followRedirects 设置是否重定向。
followSslRedirects 设置是否允许HTTP和HTTPS协议间的重定向,优先满足followRedirects。
CookieJar 设置Cookie的保存和读取机制,默认是没有Cookie处理的。
cache 设置网络响应缓存,可在无网环境时读取缓存数据。
dns 设置DNS服务,用于查找host于ip地址的映射。
proxy 设置代理,优先级高于proxySelector。
proxySelector 设置proxy选择器,可根据不同的url设置不同的选择器,当[proxy]设置为null时可用,类似PAC和全局代理。有时可通过ProxySelector防止抓包,绕过代理
proxyAuthenticator 设置代理服务器的授权,而authenticator是设置原始服务器的授权。
socketFactory 用于创建连接的sockets对象。
sslSocketFactory 用于创建HTPPS连接的SSLSocket对象。
x509TrustManagerOrNull X509TrustManager主要用于校验HTTPS连接中服务端的证书,一般情况下无需设置,除非使用自签名证书或者不校验。
connectionSpecs 主要用于指定HTTPS连接中可支持的TLS版本和密码套件。
protocols 设置请求协议。
hostnameVerifier 在握手期间,主要用于校验服务器的主机名是否与证书中的主机名相符,判断该连接是否有效。
certificatePinner 通过设置合法的公钥,验证服务端证书的合法性,可以将你信任的服务器证书或公钥的散列值配置到你的客户端上,只有当服务器提供的证书或公钥的散列值与客户端配置的相匹配时,才认为这个连接是安全的。称作公钥锁定或证书固定
certificateChainCleaner 用于移除不匹配的TSL链接并获取受信任的证书。
callTimeout 设置一次完整请求(dns解析、连接、写入request、服务端处理、获取response;包括重定向和网络重试)的超时时间。
connectTimeout 设置tcp连接(和target的tcp连接)的超时时间。
readTimeout 设置服务器开始发送响应数据+客户端接收完响应数据的超时时间。
writeTimeout 设置客户端开始发送请求数据+服务端接收完请求数据的超时时间。
pingInterval 设置连续两次自动ping之间的时间间隔,使用此参数自动发送ping帧,直到连接失败或关闭。这将使连接保持活动状态,并可以检测到连接失败,在适用于长连接的场景。
minWebSocketMessageToCompress 设置WebSocket消息需要压缩的最小大小,如果设置为1024,则WebSocket消息大于1024bytes后需要压缩,否则不压缩。
routeDatabase OkHttp 的一个内部机制用于追踪和管理 HTTP 连接的路由信息,无法直接设置,可以通过connectionPool() 方法获取到连接池,并通过连接池来看到具体的路由信息

什么是Request请求

Request用途

Request为一个HTTP请求,其包含了urlmethodheadersbody等网络所需配置。

总结

本章首先介绍如何用okhttp发送一个网络请求,然后分析OkhttpClient和Request的组成元素,后续看看okhttp是如何将请求发送出去的。

相关推荐
玩电脑的辣条哥2 小时前
Python如何播放本地音乐并在web页面播放
开发语言·前端·python
ew452182 小时前
ElementUI表格表头自定义添加checkbox,点击选中样式不生效
前端·javascript·elementui
suibian52352 小时前
AI时代:前端开发的职业发展路径拓宽
前端·人工智能
Moon.92 小时前
el-table的hasChildren不生效?子级没数据还显示箭头号?树形数据无法展开和收缩
前端·vue.js·html
垚垚 Securify 前沿站3 小时前
深入了解 AppScan 工具的使用:筑牢 Web 应用安全防线
运维·前端·网络·安全·web安全·系统安全
工业甲酰苯胺5 小时前
Vue3 基础概念与环境搭建
前端·javascript·vue.js
mosquito_lover17 小时前
怎么把pyqt界面做的像web一样漂亮
前端·python·pyqt
柴柴的小记9 小时前
前端vue引入特殊字体不生效
前端·javascript·vue.js
柠檬豆腐脑9 小时前
从前端到全栈:新闻管理系统及多个应用端展示
前端·全栈
bin915310 小时前
DeepSeek 助力 Vue 开发:打造丝滑的颜色选择器(Color Picker)
前端·javascript·vue.js·ecmascript·deepseek