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

Spring WebFlux如何接收同名multipart/form-data参数?

如何在Spring WebFlux控制器中接收multipart/form-data格式的同名ids参数?

问题场景

前端以multipart/form-data格式提交多个name为ids的参数,请求体示例如下:

Content-Disposition: form-data; name="ids"

30
-----------------------------313589022531437741264012237550
Content-Disposition: form-data; name="ids"

225
-----------------------------313589022531437741264012237550
Content-Disposition: form-data; name="ids"

226
-----------------------------313589022531437741264012237550
Content-Disposition: form-data; name="ids"

尝试用以下Spring WebFlux控制器代码接收:

@PostMapping(value = "/create", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<String> create(@RequestPart("ids") List<Long> ids) {
// ...
}

使用List<Long>或Long[]类型均无法正常接收,测试请求代码如下:

MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
bodyBuilder.part("ids", 22);
bodyBuilder.part("ids", 33);

webTestClient.post()
        .uri("/create")
        .contentType(MediaType.MULTIPART_FORM_DATA)
        .body(BodyInserters.fromMultipartData(bodyBuilder.build()))
        .exchange()
        .expectStatus().isOk();

出现错误:

org.springframework.web.server.ServerWebInputException: 400 BAD_REQUEST "Failed to read HTTP message"; nested exception is org.springframework.core.codec.DecodingException: JSON decoding error: Cannot deserialize value of type `java.util.ArrayList<java.lang.Integer>` from Integer value (token `JsonToken.VALUE_NUMBER_INT`); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.util.ArrayList<java.lang.Integer>` from Integer value (token `JsonToken.VALUE_NUMBER_INT`)
 at [Source: (org.springframework.core.io.buffer.DefaultDataBuffer$DefaultDataBufferInputStream); line: 1, column: 1]
    at org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver.handleReadError(AbstractMessageReaderArgumentResolver.java:224)
    at org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver.lambda$readBody$3(AbstractMessageReaderArgumentResolver.java:190)
    at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94)

错误原因

@RequestPart默认会将每个表单part视为独立的JSON数据进行解析,但这里每个ids参数都是单个数值,并非JSON数组。当尝试用List<Long>接收时,Jackson会试图把单个数值反序列化为List,从而触发类型不匹配的错误。

解决方案

方案1:改用@RequestParam接收(推荐)

@RequestParam可以自动收集同名的表单参数为集合,不管是application/x-www-form-urlencoded还是multipart/form-data格式都适用:

@PostMapping(value = "/create", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<String> create(@RequestParam("ids") List<Long> ids) {
    // 处理ids列表
    return Mono.just("处理完成,共接收" + ids.size() + "个ID");
}

方案2:用Flux<Part>手动处理多个part

如果必须使用@RequestPart,可以通过Flux<Part>接收所有name为ids的part,再逐个解析内容并收集为List:

import org.springframework.http.codec.multipart.Part;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@PostMapping(value = "/create", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<String> create(@RequestPart("ids") Flux<Part> idsParts) {
    return idsParts
            // 逐个读取part内容并转为Long类型
            .flatMap(part -> part.content()
                    .map(dataBuffer -> {
                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bytes);
                        return Long.parseLong(new String(bytes));
                    }))
            // 收集为List
            .collectList()
            .doOnNext(ids -> {
                // 处理ids列表逻辑
                System.out.println("接收的ID列表:" + ids);
            })
            .map(ids -> "处理完成,共接收" + ids.size() + "个ID");
}

说明

方案1是最简便直接的实现方式,无需额外的手动解析逻辑;方案2适用于必须使用@RequestPart的特殊场景,比如需要同时处理文件上传和表单参数的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 02:05:26