Okhttp之BridgeInterceptor阻拦器解析
假如研究过okhttp源码,应该知道okhttp的核心是阻拦器,而阻拦器所采用的设计模式是责任链设计,即每个阻拦器只解决与自己相关的业务逻辑。
之前已经分析了Okhttp的RetryAndFollowUpInterceptor的原理。
阻拦器的核心代码都在intercept(Chain chain )方法中,所以有必要彻底研究该方法是如何解决就可了解BridgeInterceptor的作用和实现。
1、okhttp中RealCall中请求网络及增加阻拦器的核心代码
如下是okhttp中RealCall.java文件中的将一个request请求,得到response的核心代码,getResponseWithInterceptorChain(),即一进方法就增加了好几个阻拦器。
Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. List<Interceptor> interceptors = new ArrayList<>(); interceptors.addAll(client.interceptors()); interceptors.add(retryAndFollowUpInterceptor); interceptors.add(new BridgeInterceptor(client.cookieJar())); interceptors.add(new CacheInterceptor(client.internalCache())); interceptors.add(new ConnectInterceptor(client)); if (!forWebSocket) { interceptors.addAll(client.networkInterceptors()); } interceptors.add(new CallServerInterceptor(forWebSocket)); Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest, this, eventListener, client.connectTimeoutMillis(), client.readTimeoutMillis(), client.writeTimeoutMillis()); return chain.proceed(originalRequest); }
2、 开始分析之前,先来理解一下正常的一次网络请求过程
一次Http请求必需要携带少量特定的Header信息,例如:以请求百度主页为例,Request中携带的信息如下:
request.png
额,貌似有点看不清,看下图,是不是高清无码
request头信息.png
标红的这些字段,即Header信息必要字段,水了这么多,就是为了说明白,一次http网络请求并不是只要要设置一个地址即可以,而是要封装一个特定的格式和必要的参数(即Header信息)。
3、BridgeInterceptor的核心伪代码
有了上面的这思想,看BridgeInterceptor的核心伪代码,是不是恍然大悟了!(具体方法作用都表明了注释)
public final class BridgeInterceptor implements Interceptor { private final CookieJar cookieJar; public BridgeInterceptor(CookieJar cookieJar) { this.cookieJar = cookieJar; } @Override 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) { //增加Content-Length头信息 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"); } //增加 Accept-Encoding信息 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()); //增加Cookie头信息 if (!cookies.isEmpty()) { requestBuilder.header("Cookie", cookieHeader(cookies)); } //增加User-Agent信息 if (userRequest.header("User-Agent") == null) { requestBuilder.header("User-Agent", Version.userAgent()); } Response networkResponse = chain.proceed(requestBuilder.build()); HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers()); Response.Builder responseBuilder = networkResponse.newBuilder() .request(userRequest); //假如服务器返回的response是压缩过的,即获取GzipSource输入流,读取返回的数据 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(); }//返回并封装为key=value 形式的cookie信息 private String cookieHeader(List<Cookie> cookies) { StringBuilder cookieHeader = new StringBuilder(); for (int i = 0, size = cookies.size(); i < size; i++) { if (i > 0) { cookieHeader.append("; "); } Cookie cookie = cookies.get(i); cookieHeader.append(cookie.name()).append('=').append(cookie.value()); } return cookieHeader.toString(); }}
3.1 方法注释已增加到method上
即获取到客户创立request对象,而后在该基础上增加http请求必要的头信息。假如返回的response信息是压缩后的,在通过okio压缩输入流解决response。
3.2 再来看看构造方法中传入的CookieJar
public BridgeInterceptor(CookieJar cookieJar)
构造中穿传入的CookieJar,会通过cookieHeader()方法,封装为key=value的形式,增加到Header信息中的cookie字段中。
4、总结一下BridgeInterceptor的作用:
4.1 封装request头信息
4.2 解决cookie信息
4.3 解决服务器压缩后的response
说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Okhttp之BridgeInterceptor阻拦器解析
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Okhttp之BridgeInterceptor阻拦器解析