热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

OkHttp之BridgeInterceptor简单分析

在《Okhttp源码简单解析(一)》这篇博客简单分析了Okhttp请求的执行流程,通过该篇博客我们知道OkHttp的核心网络请求中内置“拦截器”发挥了重大作用;本篇就对OkHttp

在《 Okhttp源码简单解析(一) 》这篇博客简单分析了Okhttp请求的执行流程,通过该篇博客我们知道OkHttp的核心网络请求中内置“拦截器”发挥了重大作用;本篇就对OkHttp内置拦截器链上第二个拦截器BridgeInterceptor的 作用进行简单的分析(第一个拦截器为RetryAndFollowUpInterceptor,因为本系列博客逻辑顺序关系,这个拦截器放后面讲解)。

Bridge,桥,什么桥?当然是链接客户端代码和网络代码的桥梁。正如官方对此类的注释所说: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.
该拦截器是链接客户端代码和网络代码的桥梁,它首先将客户端构建的Request对象信息构建成真正的网络请求;然后发起网络请求,最后就是讲服务器返回的消息封装成一个Response对象。

所以BridgeInterceptor的作用大体体现如下(既然是拦截器当然是核心逻辑是intercept方法中):

 public Response intercept(Chain chain) throws IOException {
//1.对Request进行处理
Request newRequest = builderNetWorkRequestFromUserRequest();

//2 调用后续的内置拦截器,返回服务器请求
Response networkRespOnse= chain.proceed(requestBuilder.build());

//对Response进行处理,并返回Response对象
handleResponse();

return networkResponse ;
}

在进一步分析BridgeInterceptor之前,在说一点“课外”的知识,简单看一下一个正真的http请求都包含了什么:为此,我在浏览器地址栏里请求了我一片博客的地址,用FireBug查看其网络请求得到如图信息:
这里写图片描述

可以发现除了请求URL之外,浏览器还给你拼接了请求头信息,所以既然上面所说BridgeInterceptor的第一步是将用户请求创建真正的Network Request,那么这些头信息也是少不了的,看看该拦截器是怎么捯饬的:

    //获取用户构建的Request对象
Request userRequest = chain.request();

Request.Builder requestBuilder = userRequest.newBuilder();

RequestBody body = userRequest.body();
//设置Content-Type
if (body != null) {
MediaType contentType = body.contentType();
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString());
}

//Content-Length和Transfer-Encoding互斥
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");
}
}

//设置Host
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}

//设置Connection头
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");
}

List<COOKIE> COOKIEs = COOKIEJar.loadForRequest(userRequest.url());
if (!COOKIEs.isEmpty()) {
requestBuilder.header("COOKIE", COOKIEHeader(COOKIEs));
}

if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}

上面的代码逻辑也很简单,就是为Request设置User-Agent、COOKIE、Accept-Encoding等相关请求头信息。到此为止一个完整的NetWork Request 就构建完毕,是时候发起真正的网络请求了。当然根据《Okhtt源码简单解析(一)》这篇所述,真正发起网络网络请求的就是连接器链上剩下拦截器的功能了:

//拦截器链继续往下运行
Response networkRespOnse= chain.proceed(requestBuilder.build());

当然就不是本篇要介绍的重点。根据拦截器的作用原理,此时剩下拦截器工作就是返回真正的网络响应了(当然此响应可能是缓存的,也可能是服务器返回的最新数据)。

//响应header, 如果没有自定义配置COOKIEJar==null,则什么都不做
HttpHeaders.receiveHeaders(COOKIEJar, userRequest.url(), networkResponse.headers());

Response.Builder respOnseBuilder= networkResponse.newBuilder()
.request(userRequest);
//判断服务器是否支持gzip压缩格式,如果支持则交给kio压缩
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);
responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));
}

return responseBuilder.build();

到此为止本篇博客就完毕了,至于网络其他相关知识,会另开一片博客说明。本篇只是假的的对该拦截器的功能最粗略基本的说明,对 COOKIEJar或者gzip压缩功能的说明以及网络知识的相关说明另开篇写之,如有不当之处欢迎批评指正


推荐阅读
author-avatar
洋索菲命_563
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有