Java 如何在带有 WebClient 的 Vertx 路由器中使用 futures
How to use futures in Vertx routers with WebClient in Java
我有一个带有路由器端点的 Vertx 应用程序:
router.route(HttpMethod.GET, Constants.ENDPOINT).blockingHandler(this::getItems);
此路由器调用一个方法,该方法应该 return 浏览器中的 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
?
在您的 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();
...
关于 async coordination 的 Vert.x 文档非常好,并且在示例中使用了 futures。这是我使用 Vert.x 期货实现它的方式:
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();
}
});
}
我有一个带有路由器端点的 Vertx 应用程序:
router.route(HttpMethod.GET, Constants.ENDPOINT).blockingHandler(this::getItems);
此路由器调用一个方法,该方法应该 return 浏览器中的 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
?
在您的 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();
...
关于 async coordination 的 Vert.x 文档非常好,并且在示例中使用了 futures。这是我使用 Vert.x 期货实现它的方式:
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();
}
});
}