You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Webflux中WebClient如何并行发送HTTP请求?

Hey there! Let's break down your problem step by step:

1. Is your current code actually running sequentially?

Yes, it is. But the culprit isn't Mono.zip—it's how you're constructing the three company request Monos.

2. Why is it sequential?

Each of your areYouInterestedToBuyCompanyX methods wraps the company request inside a flatMap on the priceMustBeComputedFirst Mono. Even though you've cached the price result, when Mono.zip subscribes to the three company Monos, the flatMap callbacks for each company get triggered one after another. This means your WebClient requests to Company A, B, C are initiated in sequence, not in parallel—hence the order you're seeing in the service logs.

3. How to fix it for parallel execution

The key is to create all three company request Monos after the price has been retrieved, and then subscribe to them all at once. Here's the adjusted code with additional optimizations:

@RestController
public class QuestionController {
    // Reuse a base WebClient instance instead of creating new ones repeatedly
    private final WebClient baseWebClient;

    @Autowired
    public QuestionController(WebClient.Builder webClientBuilder) {
        this.baseWebClient = webClientBuilder.baseUrl("http://some-service:8111").build();
    }

    @GetMapping("/question")
    public Mono<String> question(@RequestParam(value = "foo", required = false) String foo) {
        // Step 1: Fetch the price first
        return firstComputePriceBySendingRequest(foo)
                .flatMap(price -> {
                    // Now that we have the price, create all three company request Monos
                    Mono<String> companyA = areYouInterestedToBuyCompanyA(price);
                    Mono<String> companyB = areYouInterestedToBuyCompanyB(price);
                    Mono<String> companyC = areYouInterestedToBuyCompanyC(price);

                    // Zip them together—this subscribes to all three at once, triggering parallel requests
                    return Mono.zip(companyA, companyB, companyC)
                            .map(tuple3 -> computeSomethingAtTheEnd(tuple3.getT1(), tuple3.getT2(), tuple3.getT3()));
                });
    }

    private Mono<String> firstComputePriceBySendingRequest(String foo) {
        return baseWebClient.get()
                .uri("/getPriceForFoo/{foo}", foo)
                .retrieve()
                .bodyToMono(String.class);
    }

    private Mono<String> areYouInterestedToBuyCompanyA(String price) {
        return baseWebClient.mutate()
                .baseUrl("http://companyA")
                .build()
                .get()
                .uri("/areYouInterestedToBuy/{product}", price)
                .retrieve()
                .bodyToMono(String.class);
    }

    private Mono<String> areYouInterestedToBuyCompanyB(String price) {
        return baseWebClient.mutate()
                .baseUrl("http://companyB")
                .build()
                .get()
                .uri("/areYouInterestedToBuy/{product}", price)
                .retrieve()
                .bodyToMono(String.class);
    }

    private Mono<String> areYouInterestedToBuyCompanyC(String price) {
        return baseWebClient.mutate()
                .baseUrl("http://companyC")
                .build()
                .get()
                .uri("/areYouInterestedToBuy/{product}", price)
                .retrieve()
                .bodyToMono(String.class);
    }

    private String computeSomethingAtTheEnd(String t1, String t2, String t3) {
        return "some computation based on each company's response";
    }
}

Extra Tips for Better Practice

  • Reuse WebClient instances: WebClient is designed to be thread-safe and reusable. For even better efficiency, you could pre-create dedicated WebClient beans for Company A, B, and C in your configuration class instead of mutating the base client every time.
  • No more cache() needed: By nesting the company requests inside the price Mono's flatMap, we only execute the price request once—so the cache() call is no longer necessary.

Why this works

When the price Mono completes, we create all three company request Monos in one batch. Mono.zip then subscribes to all three simultaneously, which tells Reactor to initiate all three WebClient requests in parallel. You'll now see the companies receive requests at roughly the same time, instead of in sequence.

内容的提问来源于stack exchange,提问作者PatPanda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 20:53:09