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