OkHttp 请求构建和响应处理流程源码分析

我需要分析 OkHttp 中请求构建和响应处理的源码流程。让我整理一下需要涵盖的内容:

一、请求构建流程

Request 构建代码

1
2
3
val request = Request.Builder()
.url("https://api.example.com")
.build()
  1. 请求构建流程

    • Request.Builder 的使用
    • 各种组件的构建(URL、Headers、RequestBody 等)
    • 请求构建的设计模式分析
  2. Request 构建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// 典型的构建器模式实现
class Request private 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?,
val tags: Map<Class<*>, Any>
) {
// 构建器类
class Builder {
private var url: HttpUrl? = null
private var method = "GET"
private var headers = Headers.Builder()
private var body: RequestBody? = null
private var tags = mutableMapOf<Class<*>, Any>()

// 设置URL (支持多种形式)
fun url(url: String): Builder = url(url.toHttpUrl())
fun url(url: HttpUrl): Builder {
this.url = url
return this
}

// 设置请求方法
fun method(method: String, body: RequestBody?): Builder {
// 检查方法名和body的合法性
if (method.isEmpty()) throw IllegalArgumentException("method.isEmpty()")
if (method !in METHODS_ALLOWING_BODY && body != null) {
throw IllegalArgumentException("method $method must not have a request body")
}
if (method in METHODS_REQUIRING_BODY && body == null) {
throw IllegalArgumentException("method $method must have a request body")
}

this.method = method
this.body = body
return this
}

// 便捷方法: GET请求
fun get(): Builder = method("GET", null)

// 便捷方法: POST请求
fun post(body: RequestBody): Builder = method("POST", body)

// 添加Header
fun addHeader(name: String, value: String): Builder {
headers.add(name, value)
return this
}

// 设置完整Headers
fun headers(headers: Headers): Builder {
this.headers = headers.newBuilder()
return this
}

// 构建最终Request对象
fun build(): Request {
// 检查URL是否已设置
val url = checkNotNull(this.url) { "url == null" }
return Request(
url = url,
method = method,
headers = headers.build(),
body = body,
tags = tags.toMap()
)
}
}
}
  1. RequestBody 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 抽象类定义
abstract class RequestBody {
// 返回内容类型
abstract fun contentType(): MediaType?

// 返回内容长度
open fun contentLength(): Long = -1L

// 写入内容到缓冲区
abstract fun writeTo(sink: BufferedSink)

// 创建请求体的工厂方法
companion object {
// 从字符串创建
@JvmStatic
fun create(
contentType: MediaType?,
content: String
): RequestBody = create(contentType, content.toByteArray())

// 从字节数组创建
@JvmStatic
fun create(
contentType: MediaType?,
content: ByteArray
): RequestBody = create(contentType, content, 0, content.size)

// 从文件创建
@JvmStatic
fun create(file: File, contentType: MediaType?): RequestBody {
return object : RequestBody() {
override fun contentType() = contentType

override fun contentLength(): Long = file.length()

override fun writeTo(sink: BufferedSink) {
file.source().use { source ->
sink.writeAll(source)
}
}
}
}
}
}

二、响应处理流程

  1. 响应处理流程

    • Response 的结构
    • ResponseBody 的处理
    • 响应解析和转换机制
  2. Response 结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Response private constructor(
@get:JvmName("request") val request: Request,
@get:JvmName("protocol") val protocol: Protocol,
@get:JvmName("message") val message: String,
@get:JvmName("code") val code: Int,
@get:JvmName("headers") val headers: Headers,
@get:JvmName("body") val body: ResponseBody?,
@get:JvmName("networkResponse") val networkResponse: Response?,
@get:JvmName("cacheResponse") val cacheResponse: Response?,
@get:JvmName("priorResponse") val priorResponse: Response?,
internal val sentRequestAtMillis: Long,
internal val receivedResponseAtMillis: Long,
@get:JvmName("exchange") internal val exchange: Exchange?,
) {
// 检查响应是否成功
val isSuccessful: Boolean
get() = code in 200..299

// 构建器类
class Builder {
// 省略实现细节...
}

// 关闭响应体
fun close() {
body?.close()
}
}
  1. ResponseBody 处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
abstract class ResponseBody : Closeable {
// 返回内容类型
abstract fun contentType(): MediaType?

// 返回内容长度
abstract fun contentLength(): Long

// 获取字节流
abstract fun source(): BufferedSource

// 获取字节数组
fun bytes(): ByteArray {
val contentLength = contentLength()
if (contentLength > Int.MAX_VALUE) {
throw IOException("Cannot buffer entire body for content length: $contentLength")
}

val bytes = source().use { it.readByteArray() }
if (contentLength != -1L && contentLength != bytes.size.toLong()) {
throw IOException("Content-Length and stream length disagree")
}
return bytes
}

// 获取字符串
fun string(): String {
val source = source()
try {
return source.readString(source.readByteArray().size.toLong(), Charsets.UTF_8)
} finally {
source.close()
}
}
}
  1. 响应处理流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 使用Response的典型流程
val response = client.newCall(request).execute()

try {
// 1. 检查响应状态
if (response.isSuccessful) {
// 2. 获取响应体
val responseBody = response.body

// 3. 根据Content-Type处理数据
val contentType = responseBody?.contentType()

// 4. 读取响应数据
val responseString = responseBody?.string()
// 或者
val responseBytes = responseBody?.bytes()
// 或者
val responseStream = responseBody?.source()
} else {
// 处理错误响应
println("请求失败: ${response.code}")
}
} finally {
// 5. 关闭响应
response.close()
}

响应流程详解

  1. 响应创建

    • 通过拦截器链处理网络请求
    • CallServerInterceptor生成原始 Response
    • 各拦截器可能修改 Response(如缓存拦截器)
  2. 响应体流式处理

    • ResponseBody 采用流式 API
    • 数据按需加载,避免一次性加载大文件
    • 支持多种数据转换形式(string(), bytes(), source())
  3. 响应关闭机制

    • 必须手动关闭响应以释放连接
    • 适用 try-finally 模式确保资源释放
    • 未关闭的响应可能导致连接池耗尽

设计亮点分析

  1. 构建器模式的精巧应用

    • Request.Builder 和 Response.Builder 使构建过程简洁直观
    • 链式调用提高代码可读性
    • 参数验证在构建时进行,避免运行时错误
  2. 请求体的抽象设计

    • RequestBody 抽象类允许多种请求数据形式
    • 工厂方法简化常见请求体创建
    • 流式API高效处理大文件上传
  3. 响应处理的流式设计

    • 延迟加载机制减少内存占用
    • BufferedSource 接口提供灵活的数据读取方式
    • 显式关闭机制确保资源正确释放
  4. 类型安全与灵活性平衡

    • MediaType 类型处理确保内容类型正确
    • Headers 类封装HTTP头部复杂处理逻辑
    • 支持同步/异步两种处理模式

核心流程图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
请求构建流程:
Request.Builder
→ 设置URL(url())
→ 设置方法(get/post/method())
→ 设置头部(headers/addHeader())
→ 设置请求体(body)
→ build() → Request对象

响应处理流程:
Response对象
→ 检查状态码(isSuccessful)
→ 获取ResponseBody
→ 读取数据(string/bytes/source)
→ 处理业务逻辑
→ 关闭响应(close)
作者

Dench

发布于

2025-04-12

更新于

2025-04-12

许可协议

CC BY-NC-SA 4.0

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×