Spring Boot结合aws-serverless-java-container的Multipart表单上传异常
解决API Gateway + Spring Boot Lambda处理Multipart文件上传的415错误
问题背景
实现了一个Multipart POST接口,接收userId和Multipart文件作为输入,将文件保存到S3存储桶中以userId命名的文件夹内。本地运行Spring Boot应用时功能正常,但通过API Gateway调用端点时,出现415 UNSUPPORTED_MEDIA_TYPE错误,提示Content type 'application/octet-stream' not supported for bodyType=org.springframework.web.multipart.MultipartFile。
控制器代码
@RestController @RequestMapping("/api/v1/forms") public class FormController { private static final Logger log = LoggerFactory.getLogger(FormController.class); @Autowired private S3Service s3Service; @Value("${application.awsClient.legalFormsBucket}") String legalFormBucket; @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<String> uploadFile(@RequestPart("userId") String userId, @RequestPart("file") MultipartFile file, HttpServletRequest request) { log.info("Request Content-Type: {}", request.getContentType()); try { s3Service.uploadFile(userId, file); return ResponseEntity.badRequest().body(""); } catch (IOException e) { return ResponseEntity.status(500).body("File upload failed: " + e.getMessage()); } } }
Lambda处理器代码
public class StreamLambdaHandler implements RequestStreamHandler { private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler; static { try { handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(TaxtranscriptproApplication.class); handler.getServletContext().setInitParameter("binaryContentTypes", "multipart/form-data,application/octet-stream,application/pdf,image/png,image/jpeg"); } catch (ContainerInitializationException e) { e.printStackTrace(); throw new RuntimeException("Could not initialize Spring Boot application", e); } } @Override public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException { handler.proxyStream(inputStream, outputStream, context); } }
错误日志
Decoding part 'userId' No Content-Type, using application/octet-stream [java.lang.String] Decoded "92a5c4c4-8051-703c-11db-e1babe222de4" Decoding part 'file' Content-Type:application/octet-stream Could not resolve parameter [1] in public org.springframework.http.ResponseEntity<java.lang.String> com.example.taxtranscriptpro.controller.FormController.uploadFile(java.lang.String,org.springframework.web.multipart.MultipartFile,jakarta.servlet.http.HttpServletRequest): 415 UNSUPPORTED_MEDIA_TYPE "Content type 'application/octet-stream' not supported for bodyType=org.springframework.web.multipart.MultipartFile"
解决方案
1. 修正API Gateway二进制媒体类型配置
- 确保API Gateway的二进制媒体类型中添加
multipart/form-data,并且使用**通配符multipart/***覆盖所有multipart子类型(避免因请求带边界参数导致匹配失败)。 - 在API Gateway的集成请求设置中,将内容处理改为
Convert to binary (if needed),确保原始multipart二进制数据不被转成文本格式转发。
2. 调整Lambda处理器的二进制内容配置
修改Lambda初始化代码,确保Spring容器能正确识别并解码multipart请求:
static { try { handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(TaxtranscriptproApplication.class); // 扩展二进制类型覆盖范围,确保multipart请求能被正确解码 handler.getServletContext().setInitParameter("binaryContentTypes", "multipart/*,application/octet-stream,application/pdf,image/png,image/jpeg"); } catch (ContainerInitializationException e) { e.printStackTrace(); throw new RuntimeException("Could not initialize Spring Boot application", e); } }
3. 显式配置Spring Multipart解析器
添加配置类确保Lambda环境下Multipart解析正常工作:
@Configuration public class MultipartConfig { @Bean public MultipartResolver multipartResolver() { StandardServletMultipartResolver resolver = new StandardServletMultipartResolver(); return resolver; } @Bean public MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); // 设置最大上传文件大小,根据业务需求调整 factory.setMaxFileSize(DataSize.ofMegabytes(50)); factory.setMaxRequestSize(DataSize.ofMegabytes(50)); return factory.createMultipartConfig(); } }
4. 优化控制器参数注解
确保文件参数的注解明确指定需求,同时验证请求发送时文件部分的Content-Type是否正确(如PDF对应application/pdf):
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<String> uploadFile( @RequestPart("userId") String userId, @RequestPart(value = "file", required = true) MultipartFile file, HttpServletRequest request) { // 业务逻辑保持不变 }
错误原因分析
API Gateway转发请求时,将文件部分的Content-Type强制改为application/octet-stream,导致Spring的Multipart解析器无法将该类型映射到MultipartFile接口。本质是API Gateway二进制类型配置不完整,或Lambda处理器未正确解码multipart请求结构导致的。
内容的提问来源于stack exchange,提问作者Shimul
相关产品推荐
相关产品推荐

