使用Vertx编写HTTP客户端
谈谈Apache的HTTP Client
谈到HTTP客户端, 在Java界最有名的当属Apache HTTP Client库了。我相信绝大多数人在使用Apache HTTP Client时都是使用的同步版本,即请求发起后需要一直等待响应返回。如果你对程序的吞吐有着更高的要求,可能会尝试使用HttpAsyncClient
, 但是使用起来貌似并不那么优雅,而且还有点"浪费"。不优雅指的是其API的设计不够"fluent", 代码写起来跟同步调用其实很像; 而"浪费"指的是你在构造Client对象时需要创建一个IO线程池,但此线程池只能是Http Client收发请求使用,别的地方是用不了的。其实,当你需要异步HTTP客户端时,Vert.x可能更适合你。
什么时候需要异步HTTP客户端
在两种情况下你会需要一个异步HTTP客户端:一是如果你的整个程序都是建立在异步I/O的基础之上,那么你并不希望发起HTTP请求会阻塞不应该阻塞的线程; 二是你需要大量重复且快速的调用某一个HTTP接口来实现"灌库"的功能,多见于离线定时任务。例如,你需要把一个大txt文件的内容逐行读取出来然后调用对方的HTTP接口发送出去,对方告诉你最高可承受2000QPS的并发,难道你要开辟一个容量为2000的线程池来发请求吗?显然,你需要异步。
Vert.x HTTP Client基本用法
首先,你需要简单的引入一个依赖
<dependency><groupId>io.vertx</groupId><artifactId>vertx-web</artifactId><version>3.5.4</version></dependency>
就可以畅玩HTTP Client了。
一个最简单的Client长这样:
Vertx vertx = Vertx.vertx(); // (0)
HttpClient client = vertx.createHttpClient(); // (1)
client.getNow("www.baidu.com", "/", resp -> System.out.println(resp.statusCode())); // (2)TimeUnit.SECONDS.sleep(10); // (3)
(0): 先创建一个Vertx对象以提供所需线程。
(1): 构造一个HttpClient对象。
(2): 向http://www.baidu.com
发起一个GET
请求,并注册一个回调方法,在回调中我们打印出了服务器返回的状态码。
(3): 让当前线程等会。
好吧,其实这就是玩具代码,生产环境可不能这么用。但这已经足够展示出Vertx相比Apache HTTP Client更加易用了。那么接下来的问题是,怎么获取body?如下:
Handler<Buffer> bodyHandler = buffer -> System.out.println(buffer.toString()); // (0)
client.getNow("www.baidu.com", "/", resp -> resp.bodyHandler(bodyHandler)); // (1)
(0): 先定义一个处理器,用于处理HTTP body buffer,这里我们将其转成String并打印出来。
(1): 在调用getNow()
时使用lambda注册一个响应Handler,此Handler会在程序接收到并解析完成HTTP Header时调用。由于这时候body可能还没有接收完,因此要打印body, 我们需要再注册一个Handler, 也就是上一行创建的bodyHandler
,此Handler会在完整接收到响应 body 后调用,所以传进来的Buffer
对象里完整的,可以直接用。
到这里还是不够,如果baidu因为压力太大半天不发送响应怎么办?如下:
client.get("www.baidu.com", "/", resp -> resp.bodyHandler(bodyHandler)) // (0).setTimeout(1000) // (1).exceptionHandler(Throwable::printStackTrace) // (2).end(); // (3)
(0): 这里我们调用HttpClient
的get()
方法而不是getNow()
, 这两个方法的区别在于getNow()
执行完后会马上将你的请求发出去,而get()
则会返回一个HttpClientRequest
对象,它其实是在构造你的请求,而不是发送请求。
(1): 设置超时时间为1000毫秒。
(2): 注册一个异步处理器,只要调用出现错误就会执行此处理器。我们这里简单的把栈信息打印出来。
(3): 执行到这一行你的请求才会被发送,前面的步骤都只是在构造请求对象而已。
接下来,我还想添加一个Header, 想POST一些数据过去该怎么办?如下:
client.post("www.baidu.com", "/", resp -> resp.bodyHandler(bodyHandler)) // (0).setTimeout(1000).exceptionHandler(Throwable::printStackTrace).putHeader("My-Header", "HelloWorld") // (1).setChunked(true) // (2).write("Hi~") // (3).end();
(0): 我们将请求方法改成了POST。不过GET方法也可以有请求体的,不信你试试。
(1): 添加了一个自定义请求头。
(2): 如果你没有设置Content-Length
请求头,那么就必须加上这行。
(3): 在body中添加一些数据。
如果你不想用setChunked()
的话,也可以使用end()
的重载方法,直接将body中的字符串传进去:
client.post("www.baidu.com", "/", resp -> resp.bodyHandler(bodyHandler)) // (0).setTimeout(1000).exceptionHandler(Throwable::printStackTrace).putHeader("My-Header", "HelloWorld").end("Hi~"); // (0)
(0): 在end()
方法中指定要发送的数据时Vertx会自动计算出字节长度将设置请求头。
以上就是Vert.x里自带HTTP客户端的基本用法,这对于绝大多数不需要在单请求中传输大量数据的业务场景来说已经足够使用了。如果你想要更高级的功能,如自动encode, decode body成对象、传输大文件等,可以使用Vert.x的Web Client
模块,只需要多加一个依赖就可以了:
<dependency><groupId>io.vertx</groupId><artifactId>vertx-web-client</artifactId><version>3.5.4</version>
</dependency>
如何在1s内发出1000个请求
现在想另一个问题,我想让我的客户端能在1s内发出1000个请求该怎么办?这时候就需要设置一些参数了,如下:
// 构造HTTP ClientHttpClientOptions options = new HttpClientOptions().setKeepAlive(true).setConnectTimeout(1000).setIdleTimeout(10).setMaxWaitQueueSize(500) // (0).setMaxPoolSize(1000); // (1)HttpClient client = vertx.createHttpClient(options);
(0): 将请求队列的最大长度设为1500。这个参数决定了当连接池不够用时,最多可以有多少请求在排队发送,如果超了则会报错。
(1): 将连接池最大连接数设为1000。这个操作非常重要,因为HTTP协议不是全双工的,你使用一个Connection发出一个请求后,在收到响应之前这个Connection是什么也干不了的,无法复用。因此要想一次性发出1000个请求就需要使用1000条连接,这样就必须设置连接池了。如果连接池小于1000, 如500, 那么就会导致后500个请求在发送时需要等待前500个请求完成,这样就降低了吞吐。
到这里请求是发出去了,接下来怎么才能"协调"这1000个请求的结果呢?也就是说怎么才能判断出来1000个请求都发完且收到响应了,可以继续发第二批1000个请求了呢?其实这个问题只要看过我上一篇文章 使用Vert.x + SpringBoot编写业务系统 的朋友应该都知道了,就不再重复了。
使用Vertx编写HTTP客户端相关推荐
- twisted:基于python的twisted框架编写一个客户端和服务端的对话聊天空间
twisted:基于python的twisted框架编写一个客户端和服务端的对话聊天空间 目录 输出结果 实现代码 输出结果 更新-- 实现代码 #基于python的twisted框架编写一个简单的聊 ...
- python编写ftp客户端_用Python写FTP客户端程序
0 前言: ftp客户端相信大家都用过,那么我们为什么还要用Python写ftp客户端呢? 我想有两个原因: 一是写出更好的ftp客户端应用程序,方便大家使用: 二是定制一些特殊服务,例如每天定时下载 ...
- python socket recv超时_python使用多线程编写tcp客户端程序,你还没掌握吗?
这篇文章主要为大家详细介绍了python使用多线程编写tcp客户端程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 在网上浏览的时候发现很多关于此题目的程序都只能接收数据,所以随便找了个程序研究 ...
- QT应用编程: 编写MQTT客户端登录OnetNet服务器完成主题订阅与发布
一.环境介绍 QT版本: 5.12.6 编译器: MinGW 32 MQTT协议: 参照3.1.1版本文档自己编写 (不是使用QT的qmqtt) 功能介绍: 使用QT编写MQTT客户端(根据mqt ...
- 一文彻底理解Redis序列化协议,你也可以编写Redis客户端
前提 最近学习Netty的时候想做一个基于Redis服务协议的编码解码模块,过程中顺便阅读了Redis服务序列化协议RESP,结合自己的理解对文档进行了翻译并且简单实现了RESP基于Java语言的解析 ...
- 用vb编写websocket客户端示例(每秒百万弹幕吞吐量)
<websocket协议详解>教程分三篇: 什么是websocket websocket协议规范 用vb编写websocket客户端示例(每秒百万弹幕吞吐量) 文章上方有详细 ...
- C#编写OPC客户端读取OPC服务器的数据(最高效简洁版)
想要了解更多,可以添加扣扣群143440558,免费交流,免费下载以上文件,免费了解更多 编写OPC客户端,网上的资料一般是一上来就要求找OPCDAAuto.dll,其实我想说,用VS,那都是多此一举 ...
- 【Java】Java编写Telnet客户端,连接到Windows的Telnet服务器,执行命令和批处理脚本
Java编写Telnet客户端,连接到Windows的Telnet服务器,执行命令和批处理脚本,同时解决了中文乱码的问题. 源代码和Jar包在这里下载:http://download.csdn.net ...
- paho | 支持10种语言编写mqtt客户端,总有一款适合你!
1. 轻量级物联网协议 - MQTT MQTT全称 Message Queuing Telemetry Transport,即消息队列遥测传输协议,是一种基于发布/订阅(publish/subscri ...
最新文章
- poj 1860 拓扑。。
- 嵌入式 说明书 软件著作权_软件著作权详细解读
- MVC4中EasyUI Tree异步加载JSON数据生成树
- 高通量数据中批次效应的鉴定和处理(二)
- 小甲鱼OD学习第18讲
- C++ const使用情况总结
- python类的构造函数是_python类(class)的构造函数、初始化函数、析构函数
- Idea和使用git命令上传本地新项目到gitee上
- -mmin find shell 报错_[shell]find用法小结
- 【Win10技巧】如何设置win10资源管理器打开为“这台电脑”?
- 银盛支付银账通进件接口php demo 签名 上传图片 进件 获取token 超简洁sdk
- 为什么低通滤波器的作用相当于积分器
- BLDC (无刷直流电机) 六步式控制方法
- msxml4.0 sp4_MSXML4和80072efd中的安全性
- Interspeech2022论文解读 | LODR:一种更好、更轻量的语言模型融合新方式
- 窗口函数深度探索(二):控制窗口大小(UNBOUNDED、CURRENT、PRECEDING、FOLLOWING)
- 骨传导蓝牙耳机哪个牌子好?最受欢迎的五款骨传导蓝牙耳机
- Dockerfile 指令 VOLUME 介绍
- java使用正则表达式获取字符串中的所有英文单词或数字
- 为什么建议大家使用 Linux 开发?有那么爽吗?
热门文章
- HTML:p,一个有陷阱的元素
- 成都大运会「数智竞技邀请赛」启动,「开悟」平台为全球青年提供AI竞技舞台...
- python关联规则挖掘_python数据挖掘 pycaret.arules 关联规则学习
- Mac本外接显示器怎么竖过来呢?
- 细谈position属性:static、fixed、relative与absolute
- 力扣让我心碎的第十二天
- TCP/IP协议栈及网络基础,协议栈原理及实现
- 年末购机推荐,首选OPPO这两款中端旗舰王者
- Android 倒影
- java在菜单的布局实例_6.Java-GUI布局管理器