[英]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.