在上一篇文章中,我们简单分析了OkHttp的第一个拦截器RetryAndFollowUpInterceptor的处理流程,主要工作是创建了一个streamAllocation,并将streamAllocation和request传给下一个拦截器:BridgeInterceptor进行处理,并根据网络请求中的异常或响应结果判定是否需要进行重连。
所以,今天我们来分析BridgeInterceptor这个拦截器的处理流程。
简介
BridgeInterceptor,中文翻译过来即是桥接拦截器,这个拦截器的主要功能是将上一个拦截器传过来的request进行请求头处理,将协议必要的头部信息和用户定义的头信息合并,然后交由下一个拦截器进行处理,获取到Response后进行cookies和gzip处理。
源码Request部分
废话不多说,直接看BridgeInterceptor的intercept方法:
public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
RequestBody body = userRequest.body();
if (body != null) {
MediaType contentType = body.contentType();
if (contentType != null) {
//设置实体主体的媒体类型
requestBuilder.header("Content-Type", contentType.toString());
}
//实体主体的大小(单位:字节
long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {
//采用分块编码
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.
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
//获取cookies
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
//http客户端程序信息
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
//调用下一个拦截器
Response networkResponse = chain.proceed(requestBuilder.build());
}
这一段我们看到BridgeInterceptor这个拦截器主要对Request做了添加请求头字段的操作,将用户构建的Request请求转化为符合http协议的、能够进行网络访问的请求,然后再将此Request传递给下一个拦截器。
源码Response部分
接上面获取到Response后:
Response networkResponse = chain.proceed(requestBuilder.build());
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
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)));
}
return responseBuilder.build();
在拿到下一个拦截器返回的Response后,首先 通过HttpHeaders.receiveHeaders进行cookies处理保存cookies信息:
public static void receiveHeaders(CookieJar cookieJar, HttpUrl url, Headers headers) {
//如果用户没有配置自定义cookies则返回
if (cookieJar == CookieJar.NO_COOKIES) return;
//解析
List<Cookie> cookies = Cookie.parseAll(url, headers);
if (cookies.isEmpty()) return;
//存储cookies
cookieJar.saveFromResponse(url, cookies);
}
在前面Request部分,我们有看到获取cookies的方法过程:
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
CookieJar只是一个接口,我们要在程序中进行cookies操作时,一般就是实现这个接口,并添加到OkhttpClient中去
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
//在此保存cookie,如使用SharedPreferences等
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
//读取cookies,
List<Cookie> cookieList = new ArrayList<>();
//...
return cookieList;
}
})
.build();
接着,对拿到的Response判断服务器是否对响应体进行了Gzip压缩,如果进行了Gzip压缩,则需要进行Gzip解压(基于Okio),最后重新构建Response并返回给上一个拦截器。
总结
这一节我们简单解析了BridgeInterceptor的处理逻辑,整体流程还是比较简单的:
将用户构建的Request请求转化成能够进行网络访问的请求(请求头设置、cookies读取等)
将请求传递给下一个拦截器,并获取响应;
对响应进行处理(cookies处理、gzip解压等),将响应转化成用户可用的Response,返回给上级拦截器