繁体   English   中英

Spring 引导 Webflux - flatMap 是链接 http 调用的正确方法吗?

[英]Spring Boot Webflux - flatMap is the correct way to chain http calls?

关于 Spring Webflux 的小问题,以及如何“链接”http 电话。

举个具体的例子,这里是一个非常简单的示例,带有 Spring MVC,带有 rest 模板。

RestTemplate restTemplate = new RestTemplate();

        HttpEntity<StepOneRequest> stepOneRequestHttpEntity = new HttpEntity<>(new StepOneRequest("foo", "bar"));
        StepOneResponse stepOneResponse = restTemplate.postForObject("https://step-one-web-service:443/getStepTwoFromFooBar", stepOneRequestHttpEntity, StepOneResponse.class);

        HttpEntity<StepTwoRequest> stepTwoRequestHttpEntity = new HttpEntity<>(new StepTwoRequest(stepOneResponse.getTheDependencyFromStepOne()));
        StepTwoResponse stepTwoResponse = restTemplate.postForObject("https://step-two-web-service:443/getResponseFromStepTwo", stepTwoRequestHttpEntity, StepTwoResponse);

        return ResponseEntity.ok(new MyResponse(stepTwoResponse.getImportantValueFromStepTwo()));
    }

在这个片段中,我们看到非常简单。 仅初始化一个 rest 模板。

构造一个 http 请求有效载荷 object。

使用构造的 object 查询第一个外部 web 应用程序 API 得到响应。

重要的是,需要第一个 HTTP 调用的响应来进行第二个 HTTP 调用。 它们只能是顺序的,它需要第一次调用的结果,才能查询第二个 API。

然后,http 调用第二个 API。

最后,基于第二个 API 响应原请求者。

现在,如果将其翻译为 Webflux:

WebClient webClientStepOne = WebClient.create("https://step-one-web-service:443/getStepTwoFromFooBar");
        WebClient webClientStepTwo = WebClient.create("https://step-two-web-service:443/getResponseFromStepTwo");

        Mono<StepOneResponse> stepOneResponseMono = webClientStepOne.post().body(BodyInserters.fromValue(new StepOneRequest("foo", "bar"))).retrieve().bodyToMono(StepOneResponse.class);

        Mono<StepTwoResponse> stepTwoResponseMono = stepOneResponseMono.flatMap(aStepOneResponse -> webClientStepTwo.post().body(BodyInserters.fromValue(aStepOneResponse.getTheDependencyFromStepOne())).retrieve().bodyToMono(StepTwoResponse.class));

        return stepTwoResponseMono.map(aStepTwoResponse -> ResponseEntity.ok(new MyResponse(aStepTwoResponse.getImportantValueFromStepTwo())));
    }

我在这里有一个大问题。 虽然这是正确的(它产生相同的响应)这是正确的做法吗?

特别是与 flatMap 的线

Mono<StepTwoResponse> stepTwoResponseMono = stepOneResponseMono.flatMap(aStepOneResponse -> webClientStepTwo.post().body(BodyInserters.fromValue(aStepOneResponse.getTheDependencyFromStepOne())).retrieve().bodyToMono(StepTwoResponse.class));

它似乎非常不合时宜。 这里有更好的方法吗?

另外,一个附带问题,如果我需要链接 N 个 api 调用,我们真的需要 N WebClient 吗? URL 不同,不仅仅是路径,完整的 URL。 当 rest 模板只能用一个实例时,这里似乎,如果我需要调用 N 个外部服务,我需要 N 个 WebClient。

请问在这里使用 WebClient 的正确方法是什么? 请问链接 http 电话的正确方法是什么?

谢谢

我在这里有一个大问题。 虽然这是正确的(它产生相同的响应)这是正确的做法吗?

本质上,是的,你做对了。 唯一不正确的是您的 Web 客户端使用情况和您的风格。

你当然不必为每个 URI 指定一个 WebClient (你不应该,它们应该是可重用的。)所以如果你有不同的域和相同的 webclient,只需创建一个标准实例:

WebClient wc = WebClient.create();

...然后使用:

webClientStepOne.post()
                .uri("https://blah")

...在链的顶部指定具有相同实例的不同 URI。

就风格而言 - 您会注意到,当分成单独的变量并写在长行上时,代码会很快变得笨拙。 乍一看似乎违反直觉,反应式领域普遍接受的最佳实践是在单个语句中完成所有操作,将每个新方法调用格式化在单独的行上(使您能够阅读然后查看反应链的执行情况。)所以在你的情况下,它会变成:

return wc.post().uri("https://step-one-web-service:443/getStepTwoFromFooBar")
        .body(BodyInserters.fromValue(new StepOneRequest("foo", "bar")))
        .retrieve()
        .bodyToMono(StepOneResponse.class)
        .flatMap(aStepOneResponse ->
                wc.post().uri("https://step-two-web-service:443/getResponseFromStepTwo")
                        .body(BodyInserters.fromValue(aStepOneResponse.getTheDependencyFromStepOne()))
                        .retrieve()
                        .bodyToMono(StepTwoResponse.class)
        )
        .map(aStepTwoResponse ->
                ResponseEntity.ok(new MyResponse(aStepTwoResponse.getImportantValueFromStepTwo()))
        );

您可以稍微整理一下,例如通过将内部 flatmap 调用委托给单独的方法 - 但这实际上归结为偏好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM