本文主要介绍Vert.x 3.4.x 版本新组件Web Client的使用
Vert.x不久前发布了3.4.0 release版本,该版本在语言支持上新增了Scala和Kotlin的支持,新引入了Web Client和Kafka Client,同时增强了微服务组件的功能,支持多种集群管理器供开发者选择(公司一位同事是vertx-zookeeper集群管理器的开发者),除了这些还有些些微的改动,好比Auth/Security方面的加强,RxJava的支持加强等等,更多的请进入传送门。java
本文不具体对每一个新特性作分析,只针对Web Client作介绍,简单了解下3.4.x版本的Web Client和3.3.x版本的Http Client的差别。web
能够明确的是Web Client是Http Client的升级版,他继承了Http Client的功能特性好比配置,Http/2的支持,pipelining等,同时又提供了一些高级特性,好比表单提交、错误处理、30X跳转等。若是你不须要细粒度的处理http请求/响应,建议你使用Web Client,它已经为你封装了好了很简单的方法供你调用,不少API也都来自HttpClient。编程
使用Web Client前,你须要引入依赖json
<dependency> <groupId>io.vertx</groupId> <artifactId>vertx-web-client</artifactId> <version>3.4.1</version> </dependency>
建立一个默认的WebClient:api
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数据的简单请求:app
HttpRequest<Buffer> request = client.request(HttpMethod.GET,"/1.0/orders"); request.send(asyncResult -> { if (asyncResult.succeeded()) { HttpResponse<Buffer> 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}"); HttpRequest<Buffer> request = client.request(HttpMethod.POST,"/1.0/orders"); httpRequest.sendBuffer(buffer,asyncResult -> { if (asyncResult.succeeded()) { HttpResponse<Buffer> 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<Buffer>
(好比AsyncFile)流,WebClient会自动为咱们实现管道传输pump数据。由于流的长度不肯定,请求将使用chunk即分块传输。固然若是知道流的大小,你须要指定content-length
大小。
fs.open("content.txt", new OpenOptions(), fileRes -> { if (fileRes.succeeded()) { ReadStream<Buffer> fileStream = 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()) { HttpResponse<User> response = 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<HttpResponse<Buffer>>
,它能在订阅一个Single
请求事件后发送该请求,它能被屡次订阅。
做者信息
原文系力谱云旗下技术团队_云服务研发成员:David Young
首发连接:https://blog.maxleap.cn/archi...
相关文章
Maxleap Vert.x应用实践总结
次时代Java编程(一):续 vertx-sync实践
使用Vert.x构建Web服务器和消息系统
欢迎关注微信公众号