简体   繁体   English

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

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

Small question regarding Spring Webflux, and how to "chain" http calls please.关于 Spring Webflux 的小问题,以及如何“链接”http 电话。

With a concrete example, here is a very straightforward sample with Spring MVC, with a rest template.举个具体的例子,这里是一个非常简单的示例,带有 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()));
    }

In this snippet, we see very straightforward.在这个片段中,我们看到非常简单。 Initialisation of only one rest template.仅初始化一个 rest 模板。

Construction of a http request payload object.构造一个 http 请求有效载荷 object。

Use the constructed object to query a first external web application API to get a response.使用构造的 object 查询第一个外部 web 应用程序 API 得到响应。

Important, the response of the first HTTP call is needed to make the second HTTP call.重要的是,需要第一个 HTTP 调用的响应来进行第二个 HTTP 调用。 They can only be sequential, it needs the result of the first call, to be able to query the second API.它们只能是顺序的,它需要第一次调用的结果,才能查询第二个 API。

Then, the http call to the second API.然后,http 调用第二个 API。

Finally, response based on the second API to the original requester.最后,基于第二个 API 响应原请求者。

Now, if this is translated to Webflux:现在,如果将其翻译为 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())));
    }

I have one big question here.我在这里有一个大问题。 While this is correct (it yields the same response) is this the correct thing to do?虽然这是正确的(它产生相同的响应)这是正确的做法吗?

Especially, the line with the flatMap特别是与 flatMap 的线

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

It seems very out of the picture.它似乎非常不合时宜。 Is there a better way here?这里有更好的方法吗?

Also, a side question, do we really need N WebClient if I need to chain N api calls please?另外,一个附带问题,如果我需要链接 N 个 api 调用,我们真的需要 N WebClient 吗? The URLs are different, not just the path, the complete URL. URL 不同,不仅仅是路径,完整的 URL。 When rest template can do with only one instance, it seems here, I need N WebClient if I need to call N external services.当 rest 模板只能用一个实例时,这里似乎,如果我需要调用 N 个外部服务,我需要 N 个 WebClient。

What is the correct way to use WebClient here please?请问在这里使用 WebClient 的正确方法是什么? What is the correct way to chain http calls please?请问链接 http 电话的正确方法是什么?

Thank you谢谢

I have one big question here.我在这里有一个大问题。 While this is correct (it yields the same response) is this the correct thing to do?虽然这是正确的(它产生相同的响应)这是正确的做法吗?

Essentially, yes, you've done it correctly.本质上,是的,你做对了。 The only things that aren't really correct there are your Webclient usage, and your style.唯一不正确的是您的 Web 客户端使用情况和您的风格。

You certainly don't have to specify a WebClient per URI (and you shouldn't, they're meant to be reusable.) So if you have different domains and the same webclient, just create a standard instance:你当然不必为每个 URI 指定一个 WebClient (你不应该,它们应该是可重用的。)所以如果你有不同的域和相同的 webclient,只需创建一个标准实例:

WebClient wc = WebClient.create();

...and then use: ...然后使用:

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

...at the top of your chains to specify a different URI with the same instance. ...在链的顶部指定具有相同实例的不同 URI。

In terms of style - you'll have noticed the code gets unwieldy very quickly when split up into separate variables and written on long lines.就风格而言 - 您会注意到,当分成单独的变量并写在长行上时,代码会很快变得笨拙。 Counterintuitive as it might first seem, the generally accepted best practice in reactive land is to do everything in a single statement, formatting each new method call on a separate line (enabling you to read down and then see the execution of your reactive chain.) So in your case, it would become:乍一看似乎违反直觉,反应式领域普遍接受的最佳实践是在单个语句中完成所有操作,将每个新方法调用格式化在单独的行上(使您能够阅读然后查看反应链的执行情况。)所以在你的情况下,它会变成:

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()))
        );

You could tidy it up a bit maybe, for instance by delegating the inner flatmap call to a separate method - but that really just comes down to preference.您可以稍微整理一下,例如通过将内部 flatmap 调用委托给单独的方法 - 但这实际上归结为偏好。

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

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