OkHttp 是由 Square 开发的一个高效的 HTTP 客户端库,广泛应用于 Android 开发中。作为资深安卓开发工程师,我们经常需要与网络通信打交道,而 OkHttp 提供了一个简洁而强大的 API 来处理这些通信。在这篇文章中,我们将深入探讨 OkHttp3 中的 Request
类,并了解如何有效地使用它。
目录
- OkHttp3 简介
- Request 类详解
- Request 类源码分析
- 创建 Request 对象
- 设置 Request Headers
- 设置 Request Body
- 使用 Kotlin 搭建网络请求
- 总结
1. OkHttp3 简介
OkHttp 是一个现代的 HTTP & HTTP/2 客户端,适用于安卓和 Java 应用。它具有以下特点:
- 支持 HTTP/2:允许所有同一个主机的请求共享一个套接字。
- 连接池:减少延迟。
- 透明压缩:减少数据大小。
- 响应缓存:减少不必要的网络请求。
使用 OkHttp,你可以轻松地发起同步和异步的 HTTP 请求,并处理响应。接下来,我们将详细解读 OkHttp3 中的核心类之一——Request
类。
2. Request 类详解
在 OkHttp 中,Request
类用于表示一个 HTTP 请求。它包含了请求的 URL、HTTP 方法、请求头和请求体等信息。下面是 Request
类的 UML 类图:
@startuml
class Request {
- url: HttpUrl
- method: String
- headers: Headers
- body: RequestBody?
- tags: Map<Class<*>, Any>
+ url(): HttpUrl
+ method(): String
+ headers(): Headers
+ body(): RequestBody?
+ tag(): Any?
+ newBuilder(): Builder
}
@enduml
如上图所示,Request
类包含了 URL、方法、请求头、请求体和标签等属性。接下来,我们将深入分析 Request
类的源码,了解其内部实现细节。
3. Request 类源码分析
让我们直接查看 Request
类的源码,以便深入理解它的实现。以下是 Request
类的关键部分:
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>
) {
// 获取特定类型的标签
@Suppress("UNCHECKED_CAST")
fun <T> tag(type: Class<out T>): T? = tags[type] as T?
fun newBuilder(): Builder = Builder(this)
// Request 的内部 Builder 类
class Builder {
internal var url: HttpUrl? = null
internal var method: String
internal var headers: Headers.Builder
internal var body: RequestBody? = null
internal var tags: MutableMap<Class<*>, Any> = mutableMapOf()
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.headers = request.headers.newBuilder()
this.tags = request.tags.toMutableMap()
}
fun url(url: HttpUrl): Builder = apply {
this.url = url
}
fun url(url: String): Builder = apply {
this.url = HttpUrl.get(url)
}
fun header(name: String, value: String): Builder = apply {
headers[name] = value
}
fun addHeader(name: String, value: String): Builder = apply {
headers.add(name, value)
}
fun method(method: String, body: RequestBody?): Builder = apply {
if (method.isEmpty()) throw IllegalArgumentException("method.isEmpty() == true")
if (body != null && !HttpMethod.permitsRequestBody(method)) {
throw IllegalArgumentException("method $method must not have a request body.")
}
if (body == null && HttpMethod.requiresRequestBody(method)) {
throw IllegalArgumentException("method $method must have a request body.")
}
this.method = method
this.body = body
}
fun build(): Request {
return Request(
checkNotNull(url) { "url == null" },
method,
headers.build(),
body,
tags.toMap()
)
}
}
}
通过查看源码,我们可以发现 Request
类内部主要是一些属性和方法的定义,真正的构建过程是通过其内部的 Builder
类来实现的。Builder
类提供了一系列方法来设置请求的 URL、方法、头部信息和请求体等,并最终通过 build
方法创建一个 Request
对象。
URL 属性
Request
类的 url
属性是一个 HttpUrl
对象,用于表示请求的 URL。HttpUrl
类封装了 URL 的解析和验证逻辑,确保生成的 URL 是有效的。
方法
Request
类的 method
属性表示 HTTP 方法,如 GET、POST、PUT 等。Builder
类的 method
方法用于设置请求方法,并进行相应的合法性检查。
头部信息
Request
类的 headers
属性是一个 Headers
对象,表示请求的头部信息。我们可以通过 Builder
类的 header
和 addHeader
方法来设置和添加头部信息。
请求体
Request
类的 body
属性是一个 RequestBody
对象,表示请求的体内容。Builder
类的 method
方法允许我们在设置 HTTP 方法时同时指定请求体。
标签
Request
类的 tags
属性是一个 Map<Class<*>, Any>
对象,允许我们为请求附加任意类型的标签,用于在请求和响应处理过程中传递额外的信息。
接下来,我们将展示如何使用这些属性和方法来创建一个完整的 Request
对象。
4. 创建 Request 对象
创建一个 Request
对象非常简单,我们通常使用 Request.Builder
类来构建它。以下是一个简单的例子:
val request = Request.Builder()
.url("https://api.example.com/v1/users")
.build()
上面的代码创建了一个 GET 请求,URL 为 https://api.example.com/v1/users
。Request.Builder
提供了各种方法来设置请求的不同属性。
5. 设置 Request Headers
在创建 Request
对象时,我们可以通过 addHeader
或 header
方法来设置请求头。以下是一个示例:
val request = Request.Builder()
.url("https://api.example.com/v1/users")
.addHeader("Authorization", "Bearer your_token")
.addHeader("Accept",
"application/json")
.build()
上面的代码为请求添加了两个请求头,分别是 Authorization
和 Accept
。
6. 设置 Request Body
对于 POST、PUT 等需要发送数据的请求,我们需要设置请求体。在 OkHttp 中,RequestBody
类用于表示请求体。我们可以使用 RequestBody.create
方法来创建请求体。以下是一个示例:
val json = """
{
"name": "John Doe",
"age": 30
}
""".trimIndent()
val requestBody = RequestBody.create(MediaType.get("application/json; charset=utf-8"), json)
val request = Request.Builder()
.url("https://api.example.com/v1/users")
.post(requestBody)
.build()
上面的代码创建了一个 POST 请求,发送一个 JSON 格式的请求体。
7. 使用 Kotlin 搭建网络请求
现在我们已经了解了如何创建 Request
对象及其属性,接下来我们将展示如何使用 OkHttp 发起一个网络请求,并处理响应。以下是一个完整的示例:
import okhttp3.*
import java.io.IOException
fun main() {
val client = OkHttpClient()
val json = """
{
"name": "John Doe",
"age": 30
}
""".trimIndent()
val requestBody = RequestBody.create(MediaType.get("application/json; charset=utf-8"), json)
val request = Request.Builder()
.url("https://api.example.com/v1/users")
.post(requestBody)
.addHeader("Authorization", "Bearer your_token")
.addHeader("Accept", "application/json")
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
e.printStackTrace()
}
override fun onResponse(call: Call, response: Response) {
response.use {
if (!response.isSuccessful) throw IOException("Unexpected code $response")
println(response.body()?.string())
}
}
})
}
以上代码展示了如何使用 OkHttp 发送一个异步的 POST 请求,并处理响应。我们使用 OkHttpClient
创建了一个客户端实例,构建了一个带有 JSON 请求体的 Request
对象,然后通过 newCall
方法发起请求,并使用 enqueue
方法处理异步响应。
8. 总结
在这篇文章中,我们详细介绍了 OkHttp3 中的 Request
类。我们学习了如何创建 Request
对象,设置请求头和请求体,并展示了一个完整的使用示例。希望通过这篇文章,你能够更好地理解和使用 OkHttp 来处理网络请求。
如果你有任何问题或建议,欢迎在评论区留言。感谢你的阅读!
Best regards!