概述
BridgeInterceptor拦截器,按照官方的注释是
/** * Bridges from application code to network code. First it builds a network request from a user * request. Then it proceeds to call the network. Finally it builds a user response from the network * response. */
大概意思就是作为用户网络请求和真实的网络请求的桥梁,将用户的网络请求转化为真实的网络请求,将真实的网络回复(response)转化为用户的网络回复(response)
走读代码可以看到他做了几个事情
- 添加http请求的header,如Content-Type等
- 对gzip类的response进行解压操作
代码走读
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val userRequest = chain.request()
//根据userRequest构造一个新的request, 这大概就是说的Bridge的作用吧
val requestBuilder = userRequest.newBuilder()
val body = userRequest.body
if (body != null) {
val contentType = body.contentType()
if (contentType != null) {
//添加content-type
requestBuilder.header("Content-Type", contentType.toString())
}
val contentLength = body.contentLength()
if (contentLength != -1L) {
//如果contentLength存在, 则添加到Content-Lenght字段中
requestBuilder.header("Content-Length", contentLength.toString())
requestBuilder.removeHeader("Transfer-Encoding")
} else {
//如果contentLength不存在, 就认为是分块传输
requestBuilder.header("Transfer-Encoding", "chunked")
requestBuilder.removeHeader("Content-Length")
}
}
if (userRequest.header("Host") == null) {
//从url中解析出来host
requestBuilder.header("Host", userRequest.url.toHostHeader())
}
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive")
}
// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
var transparentGzip = false
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true
//默认的Accept-Encoding是gzip
requestBuilder.header("Accept-Encoding", "gzip")
}
val cookies = cookieJar.loadForRequest(userRequest.url)
if (cookies.isNotEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies))
}
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", userAgent)
}
val networkResponse = chain.proceed(requestBuilder.build())
cookieJar.receiveHeaders(userRequest.url, networkResponse.headers)
//将networkResponse转化为用户的response
val responseBuilder = networkResponse.newBuilder()
.request(userRequest)
if (transparentGzip &&
"gzip".equals(networkResponse.header("Content-Encoding"), ignoreCase = true) &&
networkResponse.promisesBody()) {
val responseBody = networkResponse.body
if (responseBody != null) {
//对gzip的返回类型进行解压
val gzipSource = GzipSource(responseBody.source())
val strippedHeaders = networkResponse.headers.newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build()
responseBuilder.headers(strippedHeaders)
val contentType = networkResponse.header("Content-Type")
responseBuilder.body(RealResponseBody(contentType, -1L, gzipSource.buffer()))
}
}
return responseBuilder.build()
}
各个header的含义
这里复习下涉及到的各个Header的含义
-
Content-Type 表示所述的媒体资源的类型,常见的有
Content-Type: text/html; charset=utf-8 Content-Type: multipart/form-data; boundary=something
-
Content-Length 表示实体内容的长度,但是有可能会不存在,具体规则参看文章https://www.cnblogs.com/lovelacelee/p/5385683.html, 主要是在http1.1及以后的版本中,如果是keep alive,则content-length与chunk必然是二选一,如果是非keep-alive,则和http1.0以后,content-Length可有可无
-
Transfer-Encoding 取值有chunked compress deflate gzip identity 。具体参看https://cloud.tencent.com/developer/section/1190008
-
Host 表示服务器的域名
-
Connection 控制网络连接是否保持打开状态,当前事务结束之后,如果发送的值是keep-alive,连接是持久的并且不关闭。这个是在http1.1之后加的特性
-
Accept-Encoding 客户端能够接受的编码格式
-
Range 告知服务端,客户端下载该文件想要从指定的位置开始下载
-
Cookie 不解释了
-
User-Agent 不解释了
CookieJar的实现
OkHttp允许客户端自己实现CookieJar,当然服务端也预定义了一些CookieJar的子类,详细查看
NoCookies
默认没有处理Cookies
RecordingCookieJar
在内存中保留了一份Cookie