响应式编程中如何处理请求体格式为form-data的数据
在响应式编程(Reactive Programming)中,尤其是使用 Spring WebFlux 开发 RESTful 接口时,我们可能需要处理 multipart/form-data 格式的请求体。如果尝试使用 @RequestParam 注解获取数据时失败,可以考虑使用 @RequestPart 注解来解决问题。
本文将分享如何正确处理 form-data 格式的请求体,以及解决 @RequestParam 获取不到数据的问题。
问题描述
当我们定义一个接口,期望通过 @RequestParam 注解从 form-data 格式的请求体中获取参数时,可能会遇到以下问题:
- 
客户端以
multipart/form-data格式发送数据,但服务器报错,提示缺少必要的参数:arduino400 BAD_REQUEST "Required request parameter 'data' is not present." - 
尝试调试发现,
@RequestParam并没有正确解析请求体中的数据。 
以下是可能的代码示例:
            
            
              less
              
              
            
          
          @Operation(summary = "测试接口", description = "返回状态200")
@PostMapping(value = "/test")
public Mono<String> test(
        @RequestParam("appid") String appid,
        @RequestParam("version") String version,
        @RequestParam("timestamp") String timestamp,
        @RequestParam("sign") String sign,
        @RequestParam("data") String data) {
    logger.info("sign - {}", sign);
    logger.info("data - {}", data);
    return Mono.just("Success");
}
        当客户端以 form-data 格式发送请求时,例如:
            
            
              bash
              
              
            
          
          POST /test
Content-Type: multipart/form-data
appid=appid&version=version×tamp=timestamp&sign=sign&data=someData
        请求可能失败,因为 @RequestParam 并未正确解析这些参数。
解决方案:使用 @RequestPart
在 Spring WebFlux 中,@RequestPart 注解可以用于接收 multipart/form-data 请求体中的字段或文件。与 @RequestParam 不同,它专门用于处理 form-data 格式中的数据。
改造代码
将参数从 @RequestParam 改为 @RequestPart,如下:
            
            
              less
              
              
            
          
          @Operation(summary = "测试接口", description = "返回状态200")
@PostMapping(value = "/test", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<String> test(
        @RequestPart("appid") String appid,
        @RequestPart("version") String version,
        @RequestPart("timestamp") String timestamp,
        @RequestPart("sign") String sign,
        @RequestPart("data") String data) {
    logger.info("appid - {}", appid);
    logger.info("version - {}", version);
    logger.info("timestamp - {}", timestamp);
    logger.info("sign - {}", sign);
    logger.info("data - {}", data);
    return Mono.just("Success");
}
        说明
- 
注解选择:
@RequestParam适用于普通的查询参数或application/x-www-form-urlencoded格式的数据。@RequestPart专用于处理multipart/form-data格式的请求体。
 - 
指定消费类型:
- 在 
@PostMapping中设置consumes = MediaType.MULTIPART_FORM_DATA_VALUE,明确告诉 Spring 这是一个multipart/form-data格式的请求。 
 - 在 
 
客户端请求示例
使用 Postman 或其他工具,发送如下请求:
            
            
              makefile
              
              
            
          
          POST http://localhost:8080/test
Content-Type: multipart/form-data
appid: appid
version: version
timestamp: timestamp
sign: sign
data: someData
        服务器将正确接收所有参数。
完整代码示例
            
            
              less
              
              
            
          
          @RestController
@RequestMapping("/api")
public class TestController {
    private static final Logger logger = LoggerFactory.getLogger(TestController.class);
    @Operation(summary = "测试接口", description = "返回状态200")
    @PostMapping(value = "/test", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Mono<String> test(
            @RequestPart("appid") String appid,
            @RequestPart("version") String version,
            @RequestPart("timestamp") String timestamp,
            @RequestPart("sign") String sign,
            @RequestPart("data") String data) {
        logger.info("appid - {}", appid);
        logger.info("version - {}", version);
        logger.info("timestamp - {}", timestamp);
        logger.info("sign - {}", sign);
        logger.info("data - {}", data);
        return Mono.just("Success");
    }
}
        总结
            
            
              go
              
              
            
          
          在响应式编程中处理 `form-data` 格式的请求体时,`@RequestParam` 无法获取请求体中的数据,可以考虑尝试使用 `@RequestPart` 注解来解析字段数据。通过明确声明消费类型为 `multipart/form-data` 并正确使用注解,我们可以轻松处理类似场景。
拙见,若是存在问题,求大佬指正。