Spring Boot接口无法解析带引号boundary的MuleSoft文件上传请求
我们有一个运行已久的Spring Boot后端服务,近期新用户使用MuleSoft调用文件上传接口时持续失败,报错信息如下:
Failed to parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
经排查,MuleSoft与curl/Postman请求的唯一差异在于:MuleSoft发送的Content-Type头中boundary值被双引号包裹。
MuleSoft请求头示例
<Header name="Content-Type">multipart/form-data; charset=UTF-8; boundary="--------------------------669816398596264398718285"</Header>
curl请求头示例
* SSL certificate verify ok. * Using HTTP2, server supports multiplexing * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x7fd656810a00) > POST /api/upload HTTP/2 > Host: myhost > user-agent: curl/7.79.1 > accept: */* > content-length: 97255 > content-type: multipart/form-data; boundary=------------------------111fd08cb4fafe1c > * Connection state changed (MAX_CONCURRENT_STREAMS == 128)! * We are completely uploaded and fine < HTTP/2 200 < date: Mon, 19 Dec 2022 04:56:25 GMT < content-length: 0
Spring Controller代码
@RestController class MyController { @PostMapping("/upload", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) @ResponseStatus(HttpStatus.OK) fun uploadDocument(@RequestPart("file") file: MultipartFile) { logger.info { "ContentType: ${file.contentType}" } logger.info { "Name: ${file.name}" } logger.info { "Byte: ${String(file.bytes)}" } } }
可正常调用的curl命令
curl -v -X POST -F file=@/Users/myhomefolder/Documents/some-file.jpg https://host-name/api/upload
无法正常调用的MuleSoft脚本
import dw::module::Multipart output multipart/form-data boundary = "---WebKitFormBoundary7MA4YWxkTrZu0gW" --- { parts : { file : { headers : { "Content-Disposition" : { "name": "file", "filename": payload.name }, "Content-Type" : "multipart/form-data" }, content : payload.byteArray } } }
请问Spring是否有配置可支持带双引号的boundary?或需补充哪些后端配置以适配不同HTTP客户端?
后端Spring Boot配置调整
1. 自定义MultipartResolver处理带引号的boundary
Spring默认的StandardServletMultipartResolver依赖Tomcat的文件上传解析器,而Tomcat原生解析逻辑不会处理boundary值的双引号,导致无法识别分隔符。可以通过自定义MultipartResolver重写解析逻辑,自动移除boundary的引号:
import org.springframework.web.multipart.MultipartException; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import javax.servlet.http.HttpServletRequest; import java.util.regex.Matcher; import java.util.regex.Pattern; public class CustomMultipartResolver extends CommonsMultipartResolver { private static final Pattern BOUNDARY_PATTERN = Pattern.compile("boundary=\"?([^\"]+)\"?", Pattern.CASE_INSENSITIVE); @Override protected String determineEncoding(HttpServletRequest request) { String contentType = request.getContentType(); if (contentType != null && contentType.contains("boundary")) { Matcher matcher = BOUNDARY_PATTERN.matcher(contentType); if (matcher.find()) { String cleanBoundary = matcher.group(1); // 重构Content-Type头,移除boundary的双引号 String updatedContentType = contentType.replaceAll("boundary=\"?([^\"]+)\"?", "boundary=" + cleanBoundary); request.setAttribute("CONTENT_TYPE", updatedContentType); } } return super.determineEncoding(request); } @Override public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException { // 先处理Content-Type头再执行解析 determineEncoding(request); return super.resolveMultipart(request); } }
然后在配置类中注册这个自定义解析器:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.multipart.MultipartResolver; @Configuration public class MultipartConfig { @Bean(name = "multipartResolver") public MultipartResolver customMultipartResolver() { CustomMultipartResolver resolver = new CustomMultipartResolver(); // 按需配置文件上传参数,比如最大文件大小 resolver.setMaxUploadSize(10 * 1024 * 1024); resolver.setMaxUploadSizePerFile(5 * 1024 * 1024); return resolver; } }
2. 升级Spring Boot及Tomcat版本
Tomcat 9.0.60及以上版本已经修复了带引号boundary的解析问题,对应的Spring Boot版本(如2.7.x及以上)集成了该版本的Tomcat。如果项目版本允许,直接升级Spring Boot依赖即可原生支持带引号的boundary,无需自定义代码。
前端MuleSoft端调整建议
如果后端暂时无法修改,也可以要求MuleSoft调整请求构造逻辑:
- 修改DataWeave脚本中的输出配置,移除boundary值的双引号:
output multipart/form-data boundary = ---WebKitFormBoundary7MA4YWxkTrZu0gW - 检查MuleSoft HTTP请求组件的配置,确保Content-Type头中的boundary没有被自动添加引号
内容的提问来源于stack exchange,提问作者xbmono

