BridgeInterceptor是位于重定向拦截器之后的第一个拦截器,也就是说在okhttp默认实现的5个拦截器中的第二个。
他的作用,顾名思义就是用户程序层面和网络层面的桥梁。他会根据用户请求来构建真正要用到的网络请求,又会根据服务器返回的网络请求,来构建用户层面的请求。
从源代码分析,以小一点的视角看,他其实主要就是对请求报文的首部行做一些的设置,对响应报文可能出现需要解压文件的情况,进行解压。
另一方面,okhttp中对cookie的相关设置也在这个拦截器中完成,okhttp是默认不使用cookie的,如果要添加cookie,需要我们在构建okhttpclient中自己实现相应的接口。
源码分析
BridgeInterceptor的代码其实并不复杂,更主要的是需要我们对http报文格式有深入的理解,才能理解BridgeInterceptor的工作流程。
//直接看intercept方法
@Override public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();//获取chain上传递的request
Request.Builder requestBuilder = userRequest.newBuilder();
//设置request的builder(用来生成真正用于网络层面的request)
RequestBody body = userRequest.body();//还是应用程序层面的request
if (body != null) {
MediaType contentType = body.contentType();
if (contentType != null) {//设置contentType,指示http中entity body的类型
requestBuilder.header("Content-Type", contentType.toString());
}
long contentLength = body.contentLength();
if (contentLength != -1) {//使用content-length指示被发送对象的字节数
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {//使用分块运输,不需要content-length
requestBuilder.header("Transfer-Encoding", "chunked");
requestBuilder.removeHeader("Content-Length");
}
}
if (userRequest.header("Host") == null) {//设置主机地址
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}
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.
//机翻:如果我们添加一个“Accept-Encoding: gzip”头域,我们还负责解压传输流。
boolean transparentGzip = false;//所以这里要加一个指示器,后面可能要解析
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {//Accept-Encoding和要不要压缩有关,Range和断点续传有关,这里的条件还不是很明白
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");//希望服务器发送压缩的response
}
//这里的cookie操作,需要我们自己传入cookieJar(在设置okhttp-client的时候)
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {//添加cookie
requestBuilder.header("Cookie", cookieHeader(cookies));
// cookieHeader这个方法不太复杂,就是遍历缓存把header取出来,这里就不放这个方法的详细实现了
}
if (userRequest.header("User-Agent") == null) {//指明用户代理(向服务器发请求的浏览器类型)
requestBuilder.header("User-Agent", Version.userAgent());//默认是okhttp/3.12.0
}
Response networkResponse = chain.proceed(requestBuilder.build());
//交给下一个拦截器处理request
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
//这部分是对cookie进行处理,同样也要自己设置了cookie,才能触发
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);//配置response
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {//解压文件,这部分的操作不是很明了
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);//对头部进行设置
String contentType = networkResponse.header("Content-Type");
responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));//对body设置
}
return responseBuilder.build();//返回response
}