OkHttp 3.x 源码解析之Interceptor 拦截器

拦截器

Java里的拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。
在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。

过滤器

过滤器可以简单理解为“取你所想取”,忽视掉那些你不想要的东西;拦截器可以简单理解为“拒你所想拒”,关心你想要拒绝掉哪些东西,比如一个BBS论坛上拦截掉敏感词汇。

1.拦截器是基于java反射机制的,而过滤器是基于函数回调的。
2.过滤器依赖于servlet容器,而拦截器不依赖于servlet容器。
3.拦截器只对action起作用,而过滤器几乎可以对所有请求起作用。
4.拦截器可以访问action上下文、值栈里的对象,而过滤器不能。
5.在action的生命周期里,拦截器可以多起调用,而过滤器只能在容器初始化时调用一次。
Android里面过滤器大家用的已经无法再陌生了,Filter就是一个很好的列子,在清单文件注册Filter就可以过滤启动摸某个组件的Action.

Okhttp拦截器因此应运而生,处理一次网络调用的Action拦截,做修改操作。

 

OKHTTP INTERCEPTOR

使用

okhttp拦截器用法很简单,构建OkHttpClient时候通过.addInterceptor()就可以将拦截器加入到一次会话中。

OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
1
2
3
1
2
3
拦截器

拦截器是Okhttp一种强大的机制,可以监视,重写和重试每一次请求。下面示列了一个简单的拦截器,用于记录传出的请求和传入的响应。

class LoggingInterceptor implements Interceptor {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();

long t1 = System.nanoTime();
logger.info(String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));

Response response = chain.proceed(request);

long t2 = System.nanoTime();
logger.info(String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));

return response;
}
}
呼叫chain.proceed(request)是每个拦截器实现的关键部分。这个简单的方法是所有HTTP工作发生的地方,产生满足请求的响应。

拦截器可以链接。假设您同时拥有一个压缩拦截器和一个校验和拦截器:您需要确定数据是否已压缩,然后进行校验和,或校验和然后压缩。OkHttp使用列表来跟踪拦截器,拦截器按顺序调用。

应用拦截器

拦截器被注册为应用程序或网络拦截器。我们将使用LoggingInterceptor上面定义来显示差异。

注册一个应用程序通过调用拦截器addInterceptor()上OkHttpClient.Builder:

OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();

Request request = new Request.Builder()
.url("http://www.publicobject.com/helloworld.txt")
.header("User-Agent", "OkHttp Example")
.build();

Response response = client.newCall(request).execute();
response.body().close();
URLhttp://www.publicobject.com/helloworld.txt重定向到https://publicobject.com/helloworld.txt,OkHttp自动跟随此重定向。我们的应用拦截器被调用一次,返回的响应chain.proceed()具有重定向的响应:

INFO: Sending request http://www.publicobject.com/helloworld.txt on null
User-Agent: OkHttp Example

INFO: Received response for https://publicobject.com/helloworld.txt in 1179.7ms
Server: nginx/1.4.6 (Ubuntu)
Content-Type: text/plain
Content-Length: 1759
Connection: keep-alive
我们可以看到,我们被重定向是因为response.request().url()不同request.url()。两个日志语句记录两个不同的URL。

网络拦截器

注册网络拦截器是非常相似的。调用addNetworkInterceptor()而不是addInterceptor();

OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new LoggingInterceptor())
.build();

Request request = new Request.Builder()
.url("http://www.publicobject.com/helloworld.txt")
.header("User-Agent", "OkHttp Example")
.build();

Response response = client.newCall(request).execute();
response.body().close();

当我们运行这个代码时,拦截器运行两次。一次为初始请求http://www.publicobject.com/helloworld.txt,另一个为重定向https://publicobject.com/helloworld.txt。

INFO: Sending request http://www.publicobject.com/helloworld.txt on Connection{www.publicobject.com:80, proxy=DIRECT hostAddress=54.187.32.157 cipherSuite=none protocol=http/1.1}
User-Agent: OkHttp Example
Host: www.publicobject.com
Connection: Keep-Alive
Accept-Encoding: gzip
INFO: Received response for http://www.publicobject.com/helloworld.txt in 115.6ms
Server: nginx/1.4.6 (Ubuntu)
Content-Type: text/html
Content-Length: 193
Connection: keep-alive
Location: https://publicobject.com/ www.tengxun10001.cn helloworld.txt

INFO: Sending request https://publicobject.com/helloworld.txt on Connection{publicobject.com:443, proxy=DIRECT hostAddress=54.187.32.157 cipherSuite=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA protocol=http/1.1}
User-Agent: OkHttp Example
Host: publicobject.com
Connection: Keep-Alive
Accept-Encoding: gzip

INFO: Received response for https://publicobject.com/helloworld.txt in 80.9ms
Server: nginx/1.4.6 (Ubuntu)
Content-Type: text/plain
Content-Length: 1759
Connection: keep-alive
网络请求还包含更多的数据,例如Accept-Encoding: gzip由OkHttp添加的标题来广播支持响应压缩。网络拦截器Chain具有非空值Connection,可用于询问用于连接到Web服务器的IP地址和TLS配置。

在应用拦截器和网络拦截器之间如何让进行选择?

每个拦截链有相对优点。

应用拦截器

不需要担心中间响应,如重定向和重试。
总是调用一次,即使从缓存提供HTTP响应。
遵守应用程序的原始意图。不注意OkHttp注入的头像If-None-Match。
允许短路和不通话Chain.proceed()。
允许重试并进行多次呼叫Chain.proceed()。
网络拦截器

能够对重定向和重试等中间响应进行操作。
不调用缓存的响应来短路网络。
观察数据,就像通过网络传输一样。
访问Connection该请求。
重写请求

拦截器可以添加,删除或替换请求头。还可以转换具有一个请求的正文。例如,如果连接到已知支持它的Web服务器,则可以使用应用程序拦截器添加请求体压缩。

final class GzipRequestInterceptor implements Interceptor {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null |www.jnd3658.cn| originalRequest.header ("Content-Encoding") != null) {
return chain.proceed(originalRequest);
}

Request compressedRequest = originalRequest.newBuilder()
.header("Content-Encoding", "gzip")
.method(originalRequest.method(), gzip(originalRequest.body()))
.build();
return chain.proceed(compressedRequest);
}

private RequestBody gzip(final RequestBody body) {
return new RequestBody() {
@Override public MediaType contentType() {
return body.contentType();
}

@Override public long contentLength() {
return -1;
// We don't know the compressed length in advance!
}

@Override public void writeTo(BufferedSink sink) throws IOException {
BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
body.writeTo(gzipSink);
gzipSink.close();
}
};
}
}
重写响应

对称地拦截器可以重写响应头并转换响应体。这通常比重写请求头更危险,因为他可以篡改违反了网络服务器的数据的本意!

如果在棘手的情况,并准备应对后果,重写响应标头是解决问题的有效方式。例如,可以修复服务器配置错误的Cache-Control响应头以启用更好的响应缓存:

private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder(www.vboyl130.cn)
.header("Cache-Control", "max-age=60")
.build();
}
};
通常,这种方法在补充Web服务器上的相应修复程序时效果最好!

转载于:https://www.cnblogs.com/chenergougou/p/7116593.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/269019.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cwntos新建目录挂载磁盘_详解Linux磁盘挂载、分区、扩容操作的实现方法

概述今天主要分享下关于Linux磁盘挂载、分区、扩容操作的实现方法,先介绍下基本概念1、磁盘在Linux系统中所有的设备都会以文件的形式存储。设备一般保存在/dev目录下面,以sda、sda1、sda2 …,sdb、sdb1…,hda,hdb。现在的设备一般都是sd命名&#xff0c…

【翻译】WF从入门到精通(第六章):加载和卸载实例

上一篇:【翻译】WF从入门到精通(第五章):workflow跟踪学习完本章,你将掌握: 1.理解工作流实例为什么要卸载和重新加载及其时机 2.理解工作流实例为什么要持久化及其时机 3.搭建SQL Server 2005&am…

python人脸照片分类_Python OpenCV 人脸识别(一)

前面介绍了Numpy模块,下面再介绍一个OpenCV模块,就基于这两个库看一下当下很火的人工智能是如何实现的,我们介绍几个:人脸识别(当下非常火的)、音视频操作等等。今天先介绍一下静态图片的人脸识别,后面再介绍动态视频以…

JAVA视频教程

http://www.icoolxue.com/album/show/38 因为需要对接接口,所以需要学服务器的语言,java,新的旅程开始转载于:https://www.cnblogs.com/chuangyiyuan/p/7118551.html

万兆以太网测试仪应该具备什么功能

在以太网技术中,100BaseT是一个里程碑,确立了以太网技术在商业用途的统治地位。千兆以太网以及随后出现的万兆以太网标准是两个比较重要的标准,以太网技术通过这两个标准从商业用途的局域网技术延伸到校园网以及城域网的汇聚和骨干。 以太网…

网络技术术语英汉对照

1. ADSL (Asymmetric Digital Subscriber Line) 非对称数字环路 2. ANSI (American National Standard Institute) 美国国家标准协会 3. APIPA (Automatic Private IP Addressing) 自动私有IP寻址 4. AppleTalk 由Apple公司推出的一种多层协议,一种可路由协议组 5. ARP (Addres…

利用photoshop制作gif图片

首先准备你需要的几张素材图片 1.将素材图片根据发生的顺序放置在不同的图层 2.打开窗口下的时间轴 选择帧动画 3.创建第一张帧动画 选项卡右边这个按钮,点击这个选择新建帧 第一张图片显示其他的隐藏 就是图层那儿左边的眼睛 4.创建第二章帧 新建帧--点击第二个图层…

合同相似可逆等价矩阵的关系及性质_线性代数预习自学笔记-11:等价性与相似性...

上一篇:线性代数预习自学笔记-10:线性变换一、相似矩阵根据矩阵表示定理,我们知道任意向量空间上的任意线性变换都可以用一个相应的矩阵表示;但一个棘手的问题是,在应用这个定理时,我们不可避免地需要先知道…

光纤铜缆测试安装的基础知识你都了解了吗?

福禄克经销商—明辰智航走访了多名读者,发现他们都说自己精通测试系统设计、安装和测试,但是很多行业的新标准新要求却是很懵懂。所以,了解当前较新的性能参数,系统必须满足的各种标准和要求以支持新的应用,确保为客户…

我看windows mobile数据同步方案

距离上篇博客似乎又过了一段日子了,这段日子应该算是挣扎着过来的,从寻找同步错误的过程到使用新的解决方案,总共花了近3个星期,我想自己有必要总结下这次的经历。项目是使用C#VS2008开发的,客户端数据存储采用SQL SER…

php获取当前时间戳方法

简介 php获取时间是件很容易的事情,下面小编就过来简单的分享一下个人所学php的一些经验吧; 操作方法 1、获取当前时间方法date() 很简单,这就是获取时间的方法,格式为:date($format, $timestamp),format为格式、timestamp为时间戳…

不禁网页的浏览器_网页游戏兴衰史:「农场」没有菜,「渣渣辉」不贪玩

本文经授权转载自 | 国家人文历史ID |gjrwls作者 |巴里安200X年某月某日凌晨2点50,小明悄悄打开房门,蹑手蹑脚地走进存放笔记本电脑的房间,将拔下电源的电脑抱紧在怀里,悄悄地回了房间。一进房,小明兴奋地打开电脑&…

Java策略模式demo(打折策略例子)

策略模式:它定义了算法家族,分别封装起来,让它们之间可以相互替换。此模式让算法的改变,不会影响到使用算法的客户端。 它对一系列的算法进行封装,为所有的算法定义一个抽象的接口,并通过继承该抽象算法接…

允許Linux的snmp服務被查詢

一、Linux(RedHat)的配置打开默认的/etc/snmp/snmpd.conf文件,更改如下配置:1、查找以下字段:[Copy to clipboard] [ - ]CODE:# sec.name source communitycom2sec notConfigUser default public将"comunity&quo…

综合布线中所需要的的带宽和数据速率

术语带宽和数据速率通常可以互换使用,但如果您在布线领域工作,它们实际上是非常不同的。 您的internet提供商可能会公布每秒500兆比特(Mbps)的带宽。在这种情况下,它们实际上是指数据速率。在布线领域,带宽…

02数据结构与算法分析之---数据的两种结构

本系列是阅读《数据结构与算法应用实践教程》第2版 主编 李文书 北京大学出版社 的读书笔记,加上自己的理解,更多的是学习的记录与反思,如有不妥,欢迎指正,非常感谢。转载于:https://www.cnblogs.com/guochaoxxl/p/712…

java 多态判断非空_收藏Java 面试题全梳理

脚本之家你与百万开发者在一起来源 | Java建设者(ID:javajianshe)作者 |cxuan如若转载请联系原公众号Java 基础篇Java 有哪些特点并发性的:你可以在其中执行许多语句,而不必一次执行它面向对象的:基于类和面向对象的编程语言。独立…

4. 用MVC实现URL路由

用MVC实现URL路由原文:http://quickstarts.asp.net/3-5-extensions/mvc/MvcUrlRouting.aspx1. 介绍MVC框架使用URL路由将URL映射到控制器类及Action方法。URL路由自动解析URL中的变量,并将他们作为参数传递给Action方法。2. 默认路由MVC提供了一些默认UR…

福禄克官方经销商给您科普光纤极性基础

极性定义了流动的方向,例如磁场或电流的方向。在光纤中,极性是定向的;光信号通过光缆从一端传输到另一端。光缆一端的光纤链路传输信号(Tx)必须与另一端的相应接收器(Rx)匹配。那么,…