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

WebFlux WebFilter获取Multipart Form Data始终为空问题排查

问题原因及解决方案

核心问题分析

你遇到的问题主要来自三个关键点:

  1. 请求体的单次消费特性:WebFlux中请求体是Flux<DataBuffer>,只能被订阅消费一次。你直接调用getMultipartData()但没有将其纳入响应式处理链,导致框架不会触发请求体的解析。
  2. Mono的延迟执行特性:getMultipartData()返回的是一个延迟执行的Mono,仅调用doOnNext()或直接subscribe()不会触发实际的解析操作——必须将其加入到WebFlux的响应处理链中(即作为返回值的一部分),框架才会订阅执行。
  3. 错误终止请求链:你在multipart分支直接返回Mono.empty(),这会让WebFlux认为请求已处理完成,不会继续执行请求体解析逻辑,自然拿不到multipart数据。

修正后的代码示例

@Component
@RequiredArgsConstructor
public class WebInterceptor implements WebFilter {

    private final SecurityService securityService;
    private final WebClient webClient;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        MediaType contentType = exchange.getRequest().getHeaders().getContentType();
        if (contentType != null && contentType.isCompatibleWith(MediaType.MULTIPART_FORM_DATA)) {
            // 先处理Authorization头,避免空指针异常
            List<String> authHeaders = exchange.getRequest().getHeaders().get("Authorization");
            if (authHeaders == null || authHeaders.isEmpty()) {
                return chain.filter(exchange);
            }
            String tokenHeader = authHeaders.get(0);
            var token = securityService.doSomeThing(tokenHeader);

            // 将multipart数据解析纳入响应链,触发实际解析
            return exchange.getMultipartData()
                    .flatMap(multipartData -> {
                        // 打印测试数据
                        System.out.println("Multipart data: " + multipartData.toSingleValueMap());

                        // 正确拼接目标URI,保留原请求查询参数
                        StringBuilder targetUriBuilder = new StringBuilder(token.getUrl());
                        String rawQuery = exchange.getRequest().getURI().getRawQuery();
                        if (rawQuery != null) {
                            targetUriBuilder.append("?").append(rawQuery);
                        }

                        // 转发请求并将响应写回原请求
                        return webClient.post()
                                .uri(targetUriBuilder.toString())
                                .headers(headers -> {
                                    headers.setAll(token.getHeaders(contentType.toString()));
                                    headers.set("Authorization", tokenHeader);
                                })
                                .body(BodyInserters.fromMultipartData(multipartData))
                                .retrieve()
                                .bodyToFlux(DataBuffer.class)
                                // 将转发响应写入原exchange的响应体
                                .flatMap(dataBuffer -> exchange.getResponse().writeWith(Mono.just(dataBuffer)))
                                // 释放数据缓冲区资源,避免内存泄漏
                                .doOnTerminate(() -> DataBufferUtils.release(dataBuffer));
                    })
                    // 处理解析或转发过程中的异常
                    .onErrorResume(e -> {
                        exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
                        return exchange.getResponse().setComplete();
                    });
        } else {
            return chain.filter(exchange);
        }
    }
}

关键修正点说明

  • 将解析逻辑纳入响应链:用flatMap()关联getMultipartData()与转发逻辑,确保WebFlux框架会订阅执行请求体解析操作。
  • 正确处理响应流转:将WebClient返回的响应体写回原ServerWebExchange的响应对象,完成请求的完整闭环。
  • 空值防护:增加Authorization头的非空判断,避免空指针异常。
  • 资源管理:显式释放DataBuffer资源,防止内存泄漏。
  • URI拼接优化:正确保留原请求的查询参数,避免转发时丢失参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 05:16:22