OkHttp之Request请求
了解了OkHttp的基本用法,不急着分析OkHttp网络请求流程。先熟悉一遍源码,了解请求相关的几个类:请求Request、请求体RequestBody以及请求头Headers。
阅读源码,一方面搞懂内部实现,遇到坑可以知道在哪。另一方面,吸取代码设计经验,设计模式不是纸上谈兵。
1、Request
先看Request源码,熟悉Request请求的设计。
1.1、请求核心成员
Request类中封装了和请求相关的成员:请求地址url、请求方法method、请求头headers、请求体body。
/**
* 一个HTTP请求。 如果此类的实例[body]为null或本身immutable,则它是immutable。
*/
class Request internal constructor(
val url: HttpUrl,
val method: String,
val headers: Headers,
val body: RequestBody?,
...
){
private var lazyCacheControl: CacheControl? = null
val cacheControl: CacheControl
...
}
OkHttp用Kotlin重新实现了一遍,原先内部成员对应的getter方法已经不可用,直接访问上面定义的成员。
@Deprecated
fun url(): HttpUrl = url
@Deprecated
fun method(): String = method
@Deprecated
fun headers(): Headers = headers
@Deprecated
fun body(): RequestBody? = body
@Deprecated
fun cacheControl(): CacheControl = cacheControl
1.2、主要方法
Request还对外提供了一些操作内部成员的方法,这是日常开发中常规的实现。
fun header(name: String): String? = headers[name]
fun headers(name: String): List<String> = headers.values(name)
...
2、内部类Builder
Request的构造方法被修饰为internal,开发者应使用内部的Builder构造者来构造Request实例。
2.1、成员
Request.Builder类内部也定义了和Request一样的成员:url、method、headers、body。
internal var url: HttpUrl? = null
internal var method: String
internal var headers: Headers.Builder
internal var body: RequestBody? = null
2.2、构造Builder
Request.Builder有两个构造函数:一个无参默认构造函数,默认请求方法是GET。
constructor() {
this.method = "GET"
this.headers = Headers.Builder()
}
另一个是以Request作为参数,相当于从另一个请求复制出一个请求。
internal constructor(request: Request) {
this.url = request.url
this.method = request.method
this.body = request.body
this.tags = if (request.tags.isEmpty()) {
mutableMapOf()
} else {
request.tags.toMutableMap()
}
this.headers = request.headers.newBuilder()
}
2.3、设置网络请求url
Builder设置网络请求的地址url,参数可以是String、也可以是URL或者HttpUrl。
open fun url(url: HttpUrl): Builder = apply {
this.url = url
}
open fun url(url: String): Builder {
// Silently replace web socket URLs with HTTP URLs.
val finalUrl: String = when {
url.startsWith("ws:", ignoreCase = true) -> {
"http:${url.substring(3)}"
}
url.startsWith("wss:", ignoreCase = true) -> {
"https:${url.substring(4)}"
}
else -> url
}
return url(finalUrl.toHttpUrl())
}
open fun url(url: URL) = url(url.toString().toHttpUrl())
2.4、设置网络请求方法
通过Builder,开发者可以设置网络请求的方法,内部也提供了HTTP常见几种方法:get()、head()、post()、delete()、put()等,开发者也可以调用method()自行设置方法。关于HTTP的请求方法在RESTful 统一接口一文中有提到。
//注意GET和HEAD是不需要RequestBody的。
open fun get() = method("GET", null)
open fun head() = method("HEAD", null)
//这些方法需要RequestBody
open fun post(body: RequestBody) = method("POST", body)
open fun delete(body: RequestBody? = EMPTY_REQUEST) = method("DELETE", body)
open fun put(body: RequestBody) = method("PUT", body)
open fun patch(body: RequestBody) = method("PATCH", body)
open fun method(method: String, body: RequestBody?): Builder = apply {
...
this.method = method
this.body = body
}
2.5、build()请求实例
一切设置好之后,调用builder()构造Request实例,将内部的成员传入Request内部internal构造方法中。
open fun build(): Request {
return Request(
checkNotNull(url) { "url == null" },
method,
headers.build(),
body,
tags.toImmutableMap()
)
}
Request内部封装了body和headers,接下来继续看请求体RequestBody以及请求头Headers的源码,了解它们的内部实现。传送门:OkHttp之RequestBody请求体。