簡體   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