摘要:为此我们可以使用来发送一个比如流,会自动为我们实现管道传输数据。因为流的长度不确定,请求将使用即分块传输。方法可以被多次安全的调用,这对于无数据的请求很容易复用配置和。如此在接受响应的回调函数里可以直接得到设置的响应解码体。
本文主要介绍Vert.x 3.4.x 版本新组件Web Client的使用
Vert.x不久前发布了3.4.0 release版本,该版本在语言支持上新增了Scala和Kotlin的支持,新引入了Web Client和Kafka Client,同时加强了微服务组件的功能,支持多种集群管理器供开发者选择(公司一位同事是vertx-zookeeper集群管理器的开发者),除了这些还有些些微的改动,比如Auth/Security方面的增强,RxJava的支持增强等等,更多的请进入传送门。
本文不具体对每个新特性做分析,只针对Web Client做介绍,简单了解下3.4.x版本的Web Client和3.3.x版本的Http Client的差异。
可以明确的是Web Client是Http Client的升级版,他继承了Http Client的功能特性比如配置,Http/2的支持,pipelining等,同时又提供了一些高级特性,比如表单提交、错误处理、30X跳转等。如果你不需要细粒度的处理http请求/响应,建议你使用Web Client,它已经为你封装了好了很简单的方法供你调用,很多API也都来自HttpClient。
使用Web Client前,你需要引入依赖
io.vertx vertx-web-client 3.4.1
创建一个默认的WebClient:
WebClient client = WebClient.create(vertx);
创建一个可配置的WebClient:
WebClientOptions options = new WebClientOptions(); options.setDefaultHost("wonapi.maxleap.cn"); WebClient webClient = WebClient.create(vertx,options);
WebClientOption的配置项全部继承了HttpClientOption,你可以配置其中任意选项。如果你的应用中已经使用了HttpClient并且配置了Option,你可以复用它:
WebClient client = WebClient.wrap(httpClient);
构建一个无body数据的简单请求:
HttpRequestrequest = client.request(HttpMethod.GET,"/1.0/orders"); request.send(asyncResult -> { if (asyncResult.succeeded()) { HttpResponse response = asyncResult.result(); System.out.println("status code:"+response.statusCode()); } else { System.err.println("error:"+asyncResult.cause().getMessage()); } });
这适用于GET/OPTIONS/HEAD方式的请求,你可以设置request的query参数,比如
通过request.addQueryParam("param1", "param1_value");来添加query参数,也可以通过request.setQueryParam("param2", "another_param2_value");来覆盖query参数,你甚至可以通过request.uri("/1.0/orders?param1=param1_value2¶m2=param2_value")来放弃现有的query参数重新设置。
构建一个有body数据的请求:
Buffer buffer = Buffer.buffer("{"a":1}"); HttpRequestrequest = client.request(HttpMethod.POST,"/1.0/orders"); httpRequest.sendBuffer(buffer,asyncResult -> { if (asyncResult.succeeded()) { HttpResponse response = asyncResult.result(); System.out.println("status code:"+response.statusCode()); } else { System.err.println("error:"+asyncResult.cause().getMessage()); } });
上面send方法来发送无body数据的请求,而通过sendXXX方法可以发送一个带body数据的请求。
sendBuffer 用来发送一个buffer缓冲区数据,这个很有用,但通常我们不希望将内容全部加载到内存里,因为它可能很大,或者我们想处理很多并发请求,并且希望对每个请求使用最小值。
为此我们可以使用sendStream来发送一个ReadStream
fs.open("content.txt", new OpenOptions(), fileRes -> { if (fileRes.succeeded()) { ReadStreamfileStream = fileRes.result(); String fileLen = "1024"; // Send the file to the server using POST client .post(80, "api.maxleap.cn", "/2.0/files") .putHeader("content-length", fileLen) .sendStream(fileStream, ar -> { if (ar.succeeded()) { // Ok } }); } });
上面就是发送一个本地文件content.txt到服务器,通过流传输的方式,因为知道文件大小所以没有使用chunked分块传输。
sendJsonObject 用来发送一个json格式数据,使用它WebClient为自动为你设置Content-Type为application/json。比如:
request.sendJsonObject(new JsonObject().put("name","Jack").put("age",18));
sendJson 用来发送一个POJO,本质上是通过Json.encode来将对象转化为json字符串(通过Jackson实现)。比如:
request.sendJson(new User("jack",18));
sendForm 用来发送表单数据,使用它WebClient会自动为你设置Content-Type为application/x-www-form-urlencoded。你也可以设置Content-Type为multipart/form-data,但当前版本(目前3.4.1)不支持表单文件上传,表单文件上传将会在后续的API版本中支持。比如:
MultiMap form = MultiMap.caseInsensitiveMultiMap(); form.set("name","jack"); form.set("age","18"); client .post(80, "api.maxleap.cn", "/2.0/users") .putHeader("content-type", "multipart/form-data") .sendStream(fileStream, ar -> { if (ar.succeeded()) { // Ok } });
跟HttpClient的API类似,你可以通过request.putHeader("header1":"value1")来添加一条头信息,也可以通过MultiMap headers = request.headers();来获取头信息并操作它(add,addAll,set,setAll,remove等操作)。
send方法可以被多次安全的调用,这对于无body数据的请求很容易复用配置和HttpRequest。同时你可以在request的基础上修改请求,比如我要复用之前使用过的request,同时修改下头信息,那么我们只需要调用之前的request对象的putHeader方法即可得到我们想要的新的request。
通过调用request.timeout(10000)你可以为请求设置数据读取超时时间,如果请求在超时期限内任未返回任何数据,会将异常java.util.concurrent.TimeoutException传递给响应处理程序。
send方法接受一个回调函数,用来处理请求发送后异步接受响应结果,需要注意的是默认接受到的响应数据会全部缓冲存放在内存里(通过request.as(BodyCodec.buffer())设置),如果数据很大,建议你通过request.as(BodyCodec.pipe(writeStream))将响应传递给写入流中,你也可以通过BodyCodec实现你想要的响应体解码,比如request.as(BodyCodec.jsonObject())将响应解析为JsonObject,request.as(BodyCodec.json(User.class))将响应解析为POJO,如果你不关注响应数据,你可以通过request.as(BodyCodec.none())来忽略响应体。如此在接受响应的回调函数里可以直接得到request.as()设置的响应解码体。比如:
client .get(80, "api.maxleap.cn", "/2.0/users") .as(BodyCodec.json(User.class)) .send(ar -> { if (ar.succeeded()) { HttpResponseresponse = ar.result(); User user = response.body(); System.out.println("Received response with status code" + response.statusCode() + " with body " + user.toString()); } else { System.out.println("Something went wrong " + ar.cause().getMessage()); } });
默认情况下,你可以在处理响应时直接使用bodyAsXXX()来解析成想要的响应体,这只针对默认的request.as(BodyCodec.buffer())有效。
vertx 3.3.x的HttpClient是不支持30X重定向的,需要自己实现跳转逻辑,在3.4.x中WebClient默认为我们实现了自动重定向,我们可以在WebClientOption中配置30X重定向的配置:
WebClientOptions options = new WebClientOptions(); options .setFollowRedirects(true)//设置遵循重定向 .setMaxRedirects(5);//最大重定向次数 WebClient webClient = WebClient.create(vertx,options);
Vert.x web client 可以跟HttpClient相同的方式使用https:
client .get(443, "api.maxleap.cn", "/2.0/users") .ssl(true) .send(ar -> { if (ar.succeeded()) { // OK } });
或者直接通过决定路径发起https请求:
client .getAbs("https://api.maxleap.cn/2.0/users") .send(ar -> { if (ar.succeeded()) { // OK } });
Vert.x RxJava是一个非常受欢迎的响应式编程扩展程序包,3.4.X版本增强了对RxJava的支持,原本返回Observable的API全部更改为返回rx.Single,使其语义更加清晰,结合Vert.x Web Client,将会是一个非常强大的组合。
io.vertx.rxjava.core.Vertx rxVertx = io.vertx.rxjava.core.Vertx.vertx(); io.vertx.rxjava.ext.web.client.WebClient rxWebClient = io.vertx.rxjava.ext.web.client.WebClient.create(rxVertx); rxWebClient.get(80,"api.maxleap.cn","/2.0/users") .putHeader("header1","header1-value") .addQueryParam("query1","query1-value") .as(io.vertx.rxjava.ext.web.codec.BodyCodec.jsonObject()) .rxSend() .subscribe(response -> {}, Throwable::printStackTrace);
rxSend方法返回一个Single
作者信息
原文系力谱云旗下技术团队_云服务研发成员:David Young
首发链接:https://blog.maxleap.cn/archi...
相关文章
Maxleap Vert.x应用实践总结
次时代Java编程(一):续 vertx-sync实践
使用Vert.x构建Web服务器和消息系统
欢迎关注微信公众号
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/66998.html
摘要:主要是避免引入太多的复杂性,并且出于灵活部署的需要。以应用为例,由于实际上是在上执行,若它被阻塞,即导致后续请求全部无法得到处理。因此,最合适的做法就是对于简单业务,采用异步库。本系列其他文章入坑须知入坑须知入坑须知 最开始觉得这个系列也就最多3篇了不起了(因为事不过三嘛),没曾想居然迎来了第四篇! Kotlin 由于最近决定投身到区块链的学习当中的缘故,出于更好的理解它的基本概念,自...
摘要:本文章是蓝图系列的第二篇教程。这就是请求回应模式。好多属性我们一个一个地解释一个序列,作为的地址任务的编号任务的类型任务携带的数据,以类型表示任务优先级,以枚举类型表示。默认优先级为正常任务的延迟时间,默认是任务状态,以枚举类型表示。 本文章是 Vert.x 蓝图系列 的第二篇教程。全系列: Vert.x Blueprint 系列教程(一) | 待办事项服务开发教程 Vert.x B...
摘要:本文章是蓝图系列的第一篇教程。是事件驱动的,同时也是非阻塞的。是一组负责分发和处理事件的线程。注意,我们绝对不能去阻塞线程,否则事件的处理过程会被阻塞,我们的应用就失去了响应能力。每个负责处理请求并且写入回应结果。 本文章是 Vert.x 蓝图系列 的第一篇教程。全系列: Vert.x Blueprint 系列教程(一) | 待办事项服务开发教程 Vert.x Blueprint 系...
摘要:定时器例子之前通过调用定时器,需要传一个回调,然后所有的代码逻辑都包在里面。这里定时器会阻塞在这一行,直到一秒后才会执行下面的一行。 之前介绍过quasar,如果你希望在vert.x项目里使用coroutine的话,建议使用vertx-sync。本篇将介绍vertx-sync。 showImg(/img/bVzIsu); 本来打算另起一篇,写其他方面的东西,但是最近比较忙,就先写一篇实...
摘要:本教程是蓝图系列的第三篇教程,对应的版本为。提供了一个服务发现模块用于发布和获取服务记录。前端此微服务的前端部分,目前已整合至组件中。监视仪表板用于监视微服务系统的状态以及日志统计数据的查看。而服务则负责发布其它服务如服务或消息源并且部署。 本文章是 Vert.x 蓝图系列 的第三篇教程。全系列: Vert.x Blueprint 系列教程(一) | 待办事项服务开发教程 Vert....
阅读 2712·2021-11-22 13:54
阅读 2653·2021-10-14 09:42
阅读 3921·2021-09-28 09:47
阅读 2130·2021-09-03 10:28
阅读 1175·2021-07-26 23:38
阅读 2515·2019-08-30 15:54
阅读 2604·2019-08-29 16:35
阅读 1346·2019-08-29 15:42