当前位置: 首页 > news >正文

OkHttp: 拦截器和事件监听器

文章目录

    • 1. 拦截器
      • 1. 拦截器链
      • 2. 实际案例
        • 1. 注册为应用拦截器
        • 2. 注册为网络拦截器
      • 3. 如何选择用哪种拦截器
        • 1. 应用拦截器
        • 2. 网络层拦截器
        • 3. 重写请求
        • 4. 重写响应
      • 4. 可用性
    • 2. 事件监听器
      • 1. 请求的生命周期
      • 2. EventListener使用案例
      • 3. EventListener.Factory
      • 4. 调用失败的请求

1. 拦截器

拦截器是一种强大的机制,可以用来监测、重写、重试调用。下面是一个简单的例子,用来打印请求的输入和输出。

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;}
}

1. 拦截器链

拦截器可以形成一个拦截器链, 拦截器分为应用层拦截器、网络层拦截器,如下图所示:
在这里插入图片描述

2. 实际案例

假设我们访问的是http://www.publicobject.com/helloworld.txt,它实际上会有一个302跳转到https://publicobject.com/helloworld.txt, OkHttp会自动完成跳转。

我们用上面的LoggingInterceptor做为例子来讲解应用拦截器和网络层拦截器的区别。

1. 注册为应用拦截器
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();

输出只会有一个Request,一个Response,内部的跳转过程没有感知。以下是输出内容:

INFO: Sending request http://www.publicobject.com/helloworld.txt on null
User-Agent: OkHttp ExampleINFO: 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
2. 注册为网络拦截器
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();

输出会感知每一个Request、Response对象。以下为输出内容:

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: gzipINFO: 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/helloworld.txtINFO: 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: gzipINFO: 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、Connection这些OkHttp帮我们自动添加的头信息。

3. 如何选择用哪种拦截器

1. 应用拦截器
  • 不关心重定向、重试
  • 永远只显示一次,即使是从缓存中读取结果
  • 只关心应用的原始意图。不关心OkHttp自动添加的头,比如If-None-Match等
  • 允许短路,不调用Chain.process(request)
  • 允许重试,调用多次Chain.process(request)
2. 网络层拦截器
  • 允许修改和操作中间的请求结果和状态
  • 从缓存中读取时,不调用拦截器
  • 关心中间过程
  • 访问请求的Connection对象
3. 重写请求

拦截器可以添加、删除、修改HTTP头,甚至可以改变请求体。比如你可以在拦截器内对请求体做压缩(如果你知道Web服务器支持的话)。

final class GzipRequestInterceptor implements Interceptor {@Override public Response intercept(Interceptor.Chain chain) throws IOException {Request originalRequest = chain.request();if (originalRequest.body() == null || 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();}};}
}
4. 重写响应

重写响应可以重写响应的HTTP头、响应内容等,一般来说是不推荐的,可能会违反直觉。

比如为响应自动添加缓存头。

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().header("Cache-Control", "max-age=60").build();}
};

4. 可用性

需要okhttp 2.2以后的版本,不可以和OkUrlFactory一起工作,不能在Retrofit 1.8及以下版本使用。

2. 事件监听器

你可以通过事件知道OkHttp的内部运行状态。通过时间我们可以监控:

  • HTTP请求的大小、频率
  • 这些请求对应的网络性能

(这里提及的API还不是最终版的API,OkHttp 3.9里这个API只是非稳定的预览版,预计在3.10、3.11会稳定)

你可以通过继承EventListener并覆盖你感兴趣的事件方法来获取通知。

1. 请求的生命周期

一次普通的请求完成,会触发以下事件:
在这里插入图片描述

2. EventListener使用案例

class PrintingEventListener extends EventListener {private long callStartNanos;private void printEvent(String name) {long nowNanos = System.nanoTime();if (name.equals("callStart")) {callStartNanos = nowNanos;}long elapsedNanos = nowNanos - callStartNanos;System.out.printf("%.3f %s%n", elapsedNanos / 1000000000d, name);}@Override public void callStart(Call call) {printEvent("callStart");}@Override public void callEnd(Call call) {printEvent("callEnd");}@Override public void dnsStart(Call call, String domainName) {printEvent("dnsStart");}@Override public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {printEvent("dnsEnd");}...
}

EventListener会被所有Call共享,所以EventListener本身不能是有状态的,如果需要的话,采用EventListener.Factory

3. EventListener.Factory

Factory可以让相同的Call共用一个EventListener对象,也可以只是随机选一部分Call来监听

class MetricsEventListener extends EventListener {private static final Factory FACTORY = new Factory() {@Override public EventListener create(Call call) {if (Math.random() < 0.10) {return new MetricsEventListener(call);} else {return EventListener.NONE;}}};...
}

4. 调用失败的请求

如果是连接阶段,触发事件connectFailed(),否则触发callFailed()。失败发生的时候,有可能存在调用了start方法,但是没有调用end方法的情况。
在这里插入图片描述

相关文章:

OkHttp: 拦截器和事件监听器

文章目录 1. 拦截器1. 拦截器链2. 实际案例1. 注册为应用拦截器2. 注册为网络拦截器 3. 如何选择用哪种拦截器1. 应用拦截器2. 网络层拦截器3. 重写请求4. 重写响应 4. 可用性 2. 事件监听器1. 请求的生命周期2. EventListener使用案例3. EventListener.Factory4. 调用失败的请…...

总结一些vue3小知识2

1.el-tree-select和el-tree组件报错&#xff08;有的下拉选项选择不了&#xff0c;一点击就报错&#xff0c;但是有的却能选择&#xff0c;不会报错&#xff09; 原因:就如同v-for一样&#xff0c;需要添加key才不会出现渲染错误&#xff0c;而el-tree-select和el-tree组件需要…...

【Excel设置动态图表】

设置系列&#xff0c;设置水平轴标签。 效果如图&#xff1a; 经验总结&#xff1a; 方法1&#xff1a;如果设置A、B列为水平轴标签&#xff0c;目前无法设置只是日期为横轴&#xff0c;店铺名称只在最下面显示一个&#xff0c;只能并排1列显示。 优点&#xff1a;如果多选…...

用 C 写一个卷积神经网络

用 C 写一个卷积神经网络 深度学习领域最近发展很快&#xff0c;前一段时间读transformer论文《Attention Is All You Need》时&#xff0c;被一些神经网络和深度学习的概念搞得云里雾里&#xff0c;其实也根本没读懂。发现深度学习和传统的软件开发工程领域的差别挺大&#xf…...

直面双碳目标,优维科技携手奥意建筑打造绿色低碳建筑数智云平台

优维“双碳”战略合作建筑 为落实创新驱动发展战略&#xff0c;增强深圳工程建设领域科技创新能力&#xff0c;促进技术进步、科技成果转化和推广应用&#xff0c;根据《深圳市工程建设领域科技计划项目管理办法》《深圳市住房和建设局关于组织申报2022年深圳市工程建设领域科…...

docker 基础入门

docker 基础入门 引言 在当今快速演进的软件开发领域&#xff0c;Docker 已经成为一个革命性的工具&#xff0c;它极大地改变了我们构建、部署和管理应用程序的方式。作为一种开源容器化平台&#xff0c;Docker 提供了一个轻量级且一致的环境&#xff0c;使得软件能够在几乎任…...

HarmonyOS:NativeWindow 开发指导

场景介绍 NativeWindow 是 HarmonyOS 本地平台化窗口&#xff0c;表示图形队列的生产者端。开发者可以通过 NativeWindow 接口进行申请和提交 Buffer&#xff0c;配置 Buffer 属性信息。 针对 NativeWindow&#xff0c;常见的开发场景如下&#xff1a; ● 通过 NativeWindow…...

汉威科技传感器为农业加点“智慧”

农业是国家之根本&#xff0c;历来受到高度重视&#xff0c;在央视《传感中国》系列节目中&#xff0c;智慧农业独占一期&#xff0c;重要性不言而喻。 随着传感器、物联网、GIS、大数据、5G、人工智能、区块链等技术的快速发展&#xff0c;智慧农业成为种植、养殖行业的新趋势…...

springboot listener、filter登录实战

转载自&#xff1a; www.javaman.cn 博客系统访问&#xff1a; http://175.24.198.63:9090/front/index 登录功能 1、前端页面 采用的是layui-admin框架&#xff0c;文中的验证码内容&#xff0c;请参考作者之前的验证码功能 <!DOCTYPE html> <html lang"zh…...

【数据结构—栈的实现(数组栈)】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、栈 1.1栈的概念及结构 二、栈的实现 2.1头文件的实现—Stack.h 2.2源文件的实现—Stack.c 2.3源文件的测试—test.c 三、栈的实际测试数据展示 3.1正常的出…...

Linux安装Halo(个人网站)

项目简介 1.代码开源:Halo 的项目代码开源在 GitHub 上且处于积极维护状态&#xff0c;截止目前已经发布了 109 个版本。你也可以在上面提交你的问题或者参与代码贡献。2.易于部署:推荐使用 Docker 的方式部署 Halo&#xff0c;便于升级&#xff0c;同时避免了各种环境依赖的问…...

Java - Spring中Bean的循环依赖问题

什么是Bean的循环依赖 A对象中有B属性。B对象中有A属性。这就是循环依赖。我依赖你&#xff0c;你也依赖我。 比如&#xff1a;丈夫类Husband&#xff0c;妻子类Wife。Husband中有Wife的引用。Wife中有Husband的引用。 Spring解决循环依赖的机理 Spring为什么可以解决set s…...

使用 Python 实现简单的爬虫框架

爬虫是一种自动获取网页内容的程序&#xff0c;它可以帮助我们从网络上快速收集大量信息。在本文中&#xff0c;我们将学习如何使用 Python 编写一个简单的爬虫框架。 一、请求网页 首先&#xff0c;我们需要请求网页内容。我们可以使用 Python 的 requests 库来发送 HTTP 请…...

Activiti七大接口,28张表详解

Activiti七大接口&#xff0c;28张表详解 7大接口 RepositoryService&#xff1a;提供管理流程部署和流程定义API。 RuntimeService&#xff1a;提供运行时流程实例进行管理与控制API。 TaskService&#xff1a;提供流程任务管理API。 IdentityService&#xff1a;提供对流程…...

解决msvcr120.dll文件丢失问题

项目场景&#xff1a; 在VMware虚拟机中安装win7家庭版系统&#xff0c;安装MySQL数据库&#xff0c;部署项目文件。 问题描述 安装MySQL数据库过程中提示“msvcr120.dll文件丢失”。 原因分析&#xff1a; 提示丢失msvcr120.dll文件&#xff0c;我们首先要到C:\Windows\Sys…...

AI日报:人工智能与新材料的发现

文章目录 总览人工智能正在革命性地发现新的或更强的材料&#xff0c;这将改变制造业。更坚韧的合金问题研究解决方案 新材料人工智能存在的挑战方法探索 日本的研究人员正在使用人工智能制造更强的金属合金或发现新材料&#xff0c;并彻底改变制造过程 总览 日本的研究人员开…...

鱼fish数据集VOC+yolo-1400张(labelImg标注)

鱼类&#xff0c;是最古老的脊椎动物。易蓄积重金属。 部分不同染色体数目的杂交的后代依然有生育能力。它们几乎栖居于地球上所有的水生环境&#xff0c;从淡水的湖泊、河流到咸水的大海和大洋。 今天要介绍鱼的数据集。 数据集名称&#xff1a;鱼 fish 数据集格式&#xf…...

爬虫解析-BeautifulSoup-bs4(七)

目录 1.bs4的安装 2.bs4的语法 &#xff08;1&#xff09;查找节点 &#xff08;2&#xff09;查找结点信息 3.bs4的操作 &#xff08;1&#xff09;对本地文件进行操作 &#xff08;2&#xff09;对服务器响应文件进行操作 4.实战 beautifulsoup&#xff1a;和lxml一样…...

分类预测 | Matlab实现OOA-SVM鱼鹰算法优化支持向量机的多变量输入数据分类预测

分类预测 | Matlab实现OOA-SVM鱼鹰算法优化支持向量机的多变量输入数据分类预测 目录 分类预测 | Matlab实现OOA-SVM鱼鹰算法优化支持向量机的多变量输入数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现OOA-SVM鱼鹰算法优化支持向量机的多变量输…...

2.vue学习笔记(目录结构+模板语法+属性绑定)

文章目录 1.目录结构2.模板语法2.1.文本插值2.2.使用JavaScript表达式2.3.原始HTML 3.属性绑定3.1.简写3.2.布尔型Attribute3.3.动态绑定多个值 1.目录结构 1.vscode ——VSCode工具的配置文件夹 2.node_modules ——Vue项目的运行依赖文件夹 3.public ——资源文件夹&am…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

沙箱虚拟化技术虚拟机容器之间的关系详解

问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西&#xff0c;但是如果把三者放在一起&#xff0c;它们之间到底什么关系&#xff1f;又有什么联系呢&#xff1f;我不是很明白&#xff01;&#xff01;&#xff01; 就比如说&#xff1a; 沙箱&#…...

起重机起升机构的安全装置有哪些?

起重机起升机构的安全装置是保障吊装作业安全的关键部件&#xff0c;主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理&#xff1a; 一、超载保护装置&#xff08;核心安全装置&#xff09; 1. 起重量限制器 功能&#xff1a;实时监测起升载荷&a…...

Java中HashMap底层原理深度解析:从数据结构到红黑树优化

一、HashMap概述与核心特性 HashMap作为Java集合框架中最常用的数据结构之一&#xff0c;是基于哈希表的Map接口非同步实现。它允许使用null键和null值&#xff08;但只能有一个null键&#xff09;&#xff0c;并且不保证映射顺序的恒久不变。与Hashtable相比&#xff0c;Hash…...

6.计算机网络核心知识点精要手册

计算机网络核心知识点精要手册 1.协议基础篇 网络协议三要素 语法&#xff1a;数据与控制信息的结构或格式&#xff0c;如同语言中的语法规则语义&#xff1a;控制信息的具体含义和响应方式&#xff0c;规定通信双方"说什么"同步&#xff1a;事件执行的顺序与时序…...

【QT控件】显示类控件

目录 一、Label 二、LCD Number 三、ProgressBar 四、Calendar Widget QT专栏&#xff1a;QT_uyeonashi的博客-CSDN博客 一、Label QLabel 可以用来显示文本和图片. 核心属性如下 代码示例: 显示不同格式的文本 1) 在界面上创建三个 QLabel 尺寸放大一些. objectName 分别…...