我有一个动作,我在其中进行三次并行HTTP调用(到其他服务),然后我将响应的内容合并到一个文档中,最后我将它发送回客户端。 这是代码的工作示例:
@Inject
WSClient wsc;
public CompletionStage<Result> getUrlData() throws Exception {
List<CompletionStage<WSResponse>> stages = new ArrayList<>();
stages.add(wsc.url("http://jsonplaceholder.typicode.com/posts/1").get());
stages.add(wsc.url("http://jsonplaceholder.typicode.com/posts/2").get());
stages.add(wsc.url("http://jsonplaceholder.typicode.com/posts/3").get());
return Futures
.sequence(stages)
.thenApply(responses -> {
StringBuilder builder = new StringBuilder("[");
responses.stream().forEach(response -> builder.append(response.getBody()).append(","));
builder.deleteCharAt(builder.length()-1).append("]");
return ok(builder.toString());
})
.exceptionally(ex -> ok("{\"error\": \"An error has occurred\"}"));
如果其中一个服务不可用(您可以模拟此行为将其中一个URL的域名修改为不存在的URL),则返回的页面仅包含exceptionally()部分中包含的消息,而我需要返回正确调用的内容以及未成功调用的错误消息。有关如何做的任何提示吗?
我正在使用Play 2.5.1。
谢谢, 安德烈
答案 0 :(得分:1)
基本上,您只想为每次通话单独处理.exceptionally(..)
。这样的事情应该有效:
CompletionStage
,并包含错误处理(返回错误的JSON)Futures.sequence
顺便说一句,你可以通过使用Jackson的ObjectMapper.createObjectNode()
和ObjectMapper.createArrayNode()
以编程方式构建对象来使JSON操作更好一点:
private static final ObjectMapper mapper = new ObjectMapper();
private CompletionStage<JsonNode> getDataFromUrl(String url) {
return wsc.url(url)
.get()
.thenApply(WSResponse::asJson)
.exceptionally(ex -> {
ObjectNode error = mapper.createObjectNode();
error.put("error", ex.getMessage());
return error;
});
}
public CompletionStage<Result> getUrlData() throws Exception {
List<String> urls = new ArrayList<>();
urls.add("http://jsonplaceholder.typicode.com/posts/1");
urls.add("http://jsonplaceholder.typicode.com/posts/2");
urls.add("http://jsonplaceholder.typicode.com/posts/3");
// Convert to a list of promises
List<CompletionStage<JsonNode>> stages = urls
.stream()
.map(this::getDataFromUrl)
.collect(Collectors.toList());
return Futures
.sequence(stages)
.thenApply(responses -> {
ArrayNode arrayNode = mapper.createArrayNode();
responses.stream().forEach(arrayNode::add);
return ok(arrayNode);
});
}