本文主要介紹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服務器和消息系統
歡迎關注微信公衆號