Как использовать фьючерсы в маршрутизаторах Vertx с WebClient в Java
У меня есть приложение Vertx с конечной точкой маршрутизатора:
router.route(HttpMethod.GET, Constants.ENDPOINT).blockingHandler(this::getItems);
Этот маршрутизатор вызывает метод, который должен возвращать объект JSON в браузере или любой клиент, вызывающий эту конечную точку. На самом деле объект JSON происходит из совершенно другого сервиса. Я использую Vert.x WebClient
библиотека для вызова этой услуги.
private void getItems(RoutingContext routingContext) {
HttpServerResponse response = routingContext.response();
response.setChunked(true);
response.putHeader("content-type", "text/plain");
response.putHeader("Access-Control-Allow-Origin", "*");
JsonObject data = new JsonObject();
WebClient webClient = WebClient.create(vertx);
webClient.post(80, "my-site.com", "/api/items")
.as(BodyCodec.jsonArray())
.putHeader("Accept", "application/json")
.putHeader("Content-Type", "application/json")
.sendJsonObject(new JsonObject().put("mutator", "*"), ar -> {
if (ar.succeeded()) {
HttpResponse<JsonArray> result = ar.result();
JsonArray body = result.body();
System.out.println(body);
data.put("data", body.getJsonObject(0));
} else {
data.put("data", ar.cause().getMessage());
}
});
response.write(data.encode());
routingContext.response().end();
}
Данные, которые я получаю от my-site.com
в порядке и отображается в консоли с моей командой System.out. Проблема в том, что я не могу получить это в response.write
,
Читая, я вижу, что это связано с фьючерсами. Я не совсем понимаю эту концепцию, поэтому я много читал, но не могу найти примеров, подходящих для моего конкретного кода.
Как бы я пошел о реализации фьючерсов, чтобы данные, которые я получаю от my-site.com
попадает в мой объект Json (data
), а затем может быть использован в response.write
?
2 ответа
В ваших данных impl будет пустой объект JSON, потому что Webclient является асинхронным. Вы пишете ответ клиенту до того, как ответ от Webclient будет готов.
Переместите запись в ответ веб-клиента и завершите контекст там. Например:
...
if (ar.succeeded()) {
HttpResponse<JsonArray> result = ar.result();
JsonArray body = result.body();
System.out.println(body);
data.put("data", body.getJsonObject(0));
} else {
data.put("data", ar.cause().getMessage());
}
response.write(data.encode());
routingContext.response().end();
...
Документация Vert.x об асинхронной координации очень хороша и использует примеры в примерах. Вот как я мог бы реализовать это, используя Vert.x Futures:
private void getItems(RoutingContext routingContext) {
HttpServerResponse response = routingContext.response();
response.setChunked(true);
response.putHeader("content-type", "text/plain");
response.putHeader("Access-Control-Allow-Origin", "*");
// init a future that should hold a JsonObject result
Future<JsonObject> future = Future.future();
JsonObject data = new JsonObject();
WebClient webClient = WebClient.create(vertx);
webClient.post(80, "my-site.com", "/api/items")
.as(BodyCodec.jsonArray())
.putHeader("Accept", "application/json")
.putHeader("Content-Type", "application/json")
.sendJsonObject(new JsonObject().put("mutator", "*"), ar -> {
if (ar.succeeded()) {
HttpResponse<JsonArray> result = ar.result();
JsonArray body = result.body();
System.out.println(body);
data.put("data", body.getJsonObject(0));
// set future to be completed, with data object as its JsonObject result
future.complete(data);
} else {
data.put("data", ar.cause().getMessage());
future.complete(data);
// we can also set the future as failed and give it a Throwable
// future.fail(ar.cause());
}
});
// handle when the future is completed
future.setHandler(jsonObjectAsyncResult -> {
if(jsonObjectAsyncResult.succeeded()) {
response.write(data.encode());
routingContext.response().end();
}
});
}