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

如何高效使用Spring WebFlux的get()和post()方法处理响应(替代block()方法)

如何高效使用Spring WebFlux的get()和post()方法处理响应(替代block()方法)

嘿,我完全懂你的痛点!用block()确实能快速拿到结果,但这完全违背了Spring WebFlux的异步非阻塞设计初衷——不仅会阻塞当前线程,还会拖垮高并发场景下的性能。结合你用Spring Boot 3、JDK17的环境,还有生成文件、提取JSON关键数据的业务需求,我给你几个替代block()的实用方案:

方案一:用subscribe()异步处理独立逻辑

如果你的业务逻辑不需要同步等待请求结果再继续,直接用subscribe()来异步处理响应就行,全程不会阻塞调用线程:

针对GET请求生成文件的场景

webclient.get()
    .uri("https://testclient/")
    .headers(headers -> /* 这里传入你的HttpHeaders设置逻辑 */)
    .retrieve()
    .bodyToMono(byte[].class)
    .subscribe(bytes -> {
        // 异步写入文件
        try (FileOutputStream fos = new FileOutputStream("output.file")) {
            fos.write(bytes);
        } catch (IOException e) {
            // 按需处理文件写入异常
            e.printStackTrace();
        }
    }, error -> {
        // 处理请求失败的情况,比如打印日志或抛出业务异常
        error.printStackTrace();
    });

针对POST请求提取JSON关键数据的场景

webclient.post()
    .uri("https://testclient/")
    .contentType(MediaType.MULTIPART_FORM_DATA)
    .headers(headers -> /* 这里传入你的HttpHeaders设置逻辑 */)
    .retrieve()
    .bodyToMono(String.class)
    .subscribe(response -> {
        // 解析JSON提取关键数据
        ObjectMapper mapper = new ObjectMapper();
        try {
            JsonNode jsonNode = mapper.readTree(response);
            String targetKeyData = jsonNode.get("你需要的key").asText();
            // 把拿到的关键数据传给后续的Java应用逻辑
        } catch (JsonProcessingException e) {
            // 处理JSON解析异常
            e.printStackTrace();
        }
    }, error -> {
        // 处理请求失败的情况
        error.printStackTrace();
    });

方案二:在WebFlux Controller中直接返回Mono/Flux

如果这段代码是写在WebFlux的Controller层,要对外提供服务的话,直接返回Mono/Flux即可,框架会自动处理异步订阅和响应,完全贴合非阻塞模型:

针对GET请求返回文件资源

@GetMapping("/download-target-file")
public Mono<Resource> downloadFile() {
    return webclient.get()
        .uri("https://testclient/")
        .headers(headers -> /* 你的Header设置逻辑 */)
        .retrieve()
        .bodyToMono(byte[].class)
        .map(bytes -> new ByteArrayResource(bytes));
}

针对POST请求返回提取后的关键数据

先定义一个DTO来封装关键数据:

public class KeyDataDto {
    private String targetKey;

    // 构造方法、getter、setter
    public KeyDataDto(String targetKey) {
        this.targetKey = targetKey;
    }

    public String getTargetKey() {
        return targetKey;
    }
}

然后在Controller中返回封装好的Mono:

@PostMapping("/fetch-key-data")
public Mono<KeyDataDto> fetchKeyData() {
    return webclient.post()
        .uri("https://testclient/")
        .contentType(MediaType.MULTIPART_FORM_DATA)
        .headers(headers -> /* 你的Header设置逻辑 */)
        .retrieve()
        .bodyToMono(String.class)
        .map(response -> {
            ObjectMapper mapper = new ObjectMapper();
            try {
                JsonNode jsonNode = mapper.readTree(response);
                return new KeyDataDto(jsonNode.get("你需要的key").asText());
            } catch (JsonProcessingException e) {
                throw new RuntimeException("解析响应JSON失败", e);
            }
        });
}

方案三:用flatMap()串联多步异步操作

如果你的业务逻辑需要依赖多个请求的结果(比如先用POST拿到key,再用这个key调用GET),用flatMap()就能实现无阻塞的异步串联:

webclient.post()
    .uri("https://testclient/")
    .contentType(MediaType.MULTIPART_FORM_DATA)
    .headers(headers -> /* 你的Header设置逻辑 */)
    .retrieve()
    .bodyToMono(String.class)
    .map(response -> {
        // 从POST响应中提取key
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readTree(response).get("你需要的key").asText();
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    })
    .flatMap(extractedKey -> {
        // 用拿到的key发起GET请求
        return webclient.get()
            .uri(uriBuilder -> uriBuilder.path("https://testclient/").queryParam("key", extractedKey).build())
            .headers(headers -> /* 你的Header设置逻辑 */)
            .retrieve()
            .bodyToMono(byte[].class);
    })
    .subscribe(finalBytes -> {
        // 处理最终的GET响应,生成文件
        try (FileOutputStream fos = new FileOutputStream("file-with-key.data")) {
            fos.write(finalBytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    });

一些额外的注意事项

  • 尽量避免在同步代码中混合调用WebFlux异步方法,实在要同步的话,也得注意线程池配置,但还是优先推荐异步方案
  • 耗时的操作(比如大文件写入、复杂JSON解析)如果可能的话,最好包装成Mono/Flux,避免阻塞WebFlux的事件循环线程
  • 异常处理要优雅,除了subscribe()里的错误回调,还可以用onErrorResume()、onErrorReturn()等操作符自定义异常逻辑,比如:
.bodyToMono(byte[].class)
.onErrorResume(error -> {
    // 自定义异常处理,返回默认值或抛出业务异常
    return Mono.just(new byte[0]);
})
.subscribe(...)

备注:内容来源于stack exchange,提问作者Dev9321

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 20:09:35