【问题标题】:Merge two responses合并两个响应
【发布时间】:2022-08-23 18:37:38
【问题描述】:

firstResponsesecondResponse 应该组合成 CombinationBothResponses 并在调用 GET 端点 127.0.0.1:8081/comb 时返回。但是,第一次调用时会返回正确组合的响应:

{
    \"userId\": 1,
    \"id\": 1,
    \"title\": \"sunt aut facere repellat provident occaecati excepturi optio reprehenderit\",
    \"body\": \"quia et suscipit ...\",
    \"bodySecondResponse\": \"est rerum tempore ...\"
}

但只有 firstResponse 在所有进一步的调用中返回:

{
    \"userId\": 1,
    \"id\": 1,
    \"title\": \"sunt aut facere repellat provident occaecati excepturi optio reprehenderit\",
    \"body\": \"quia et suscipit ...\",
    \"bodySecondResponse\": null
}

如何实现始终返回组合响应?

@RestController
public class Controller {
    @Autowired Service service;

    @GetMapping(\"/comb\")
    public CompletableFuture<CombinationBothResponses> combine() {
        CompletableFuture<CombinationBothResponses> resultCallback = new CompletableFuture<>();
        service.sendTwoRequests(resultCallback);
        return resultCallback;
    }
}
@org.springframework.stereotype.Service
public class Service {
    private final Jsonb jsonb = JsonbBuilder.create();
    private final OkHttpClient client = new OkHttpClient();

    public void sendTwoRequests(CompletableFuture<CombinationBothResponses> resultCallback) {
        // 1. Send GET request 1
        Request firstRequest =
                new Request.Builder().url(\"https://jsonplaceholder.typicode.com/posts/1\").build();
        client.newCall(firstRequest).enqueue(new firstCallback(resultCallback));

        // 2. Send GET request 2
        Request secondRequest =
                new Request.Builder().url(\"https://jsonplaceholder.typicode.com/posts/2\").build();

        resultCallback.thenAccept(
                firstResponse -> {
                    client.newCall(secondRequest).enqueue(new secondCallback(resultCallback));
                });
    }
}
public class firstCallback implements Callback {
    private final Jsonb jsonb = JsonbBuilder.create();
    private final CompletableFuture<CombinationBothResponses> resultCallback;

    public firstCallback(CompletableFuture<CombinationBothResponses> resultCallback) {
        this.resultCallback = resultCallback;
    }

    @Override
    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
        var firstResponse = jsonb.fromJson(response.body().string(), CombinationBothResponses.class);
        if (response.isSuccessful()) {
            resultCallback.complete(firstResponse);
        } else {
            resultCallback.completeExceptionally(new RuntimeException());
        }
    }

    @Override
    public void onFailure(@NotNull Call call, @NotNull IOException e) {
        resultCallback.completeExceptionally(e);
    }
}
public class secondCallback implements Callback {
    private final Jsonb jsonb = JsonbBuilder.create();
    private final CompletableFuture<CombinationBothResponses> resultCallback;

    public secondCallback(CompletableFuture<CombinationBothResponses> resultCallback) {
        this.resultCallback = resultCallback;
    }

    @Override
    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
        var secondResponse = jsonb.fromJson(response.body().string(), CombinationBothResponses.class);
        if (response.isSuccessful()) {
            // 3. Combine firstResponse and secondResponse to the final response of the REST
            // controller
            resultCallback.thenApply(
                    firstResponse -> {
                        firstResponse.setBodySecondResponse(secondResponse.getBody());
                        System.out.println(firstResponse.getBodySecondResponse() != null); // true
                        return firstResponse;
                    });
        } else {
            resultCallback.completeExceptionally(new RuntimeException());
        }
    }

    @Override
    public void onFailure(@NotNull Call call, @NotNull IOException e) {
        resultCallback.completeExceptionally(e);
    }
}
@Data
@NoArgsConstructor
public class CombinationBothResponses {
    private int userId;
    private int id;
    private String title;
    private String body;

    private String bodySecondResponse;

}

    标签: java callback okhttp spring-restcontroller completable-future


    【解决方案1】:

    当您在firstCallback 中调用resultCallback.complete(firstResponse); 时,您完成了在控制器中发起的请求。

    为什么第一次答案是正确的可能取决于在代码到达secondCallback 上的thenApply 之前第一次请求完成的速度。 (之后,也许缓存使第一个请求完成得更快,代码没有时间到达thenApply)。

    您需要在每个返回CompletableFuture 的方法中拆分两个请求,然后在更高级别使用thenApplythenCombine 链接两个请求。

    【讨论】:

      【解决方案2】:

      看看我之前提供的similar answer。

      创建 2 个不同的可完成供应商,然后将它们组合起来并返回最终的组合对象。

      例如:

      //Async supplier for the api calls
      CompletableFuture<ResponseType1> cf1 = CompletableFuture.supplyAsync(() -> method(returnSyncResponseType1);
      CompletableFuture<ResponseType2> cf2 = CompletableFuture.supplyAsync(() -> returnSyncResponseType2);
      
      //composing result for these async supplier
      CompleteableFuture.allOf(resp1, resp2).thenApply(new ComposedResponse(cf1.join, cf2.join)); 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-12
        • 2016-11-30
        • 2020-11-04
        • 2020-07-18
        • 2019-01-26
        相关资源
        最近更新 更多