Spring接收multipart/related请求无法获取无Content-Disposition的部分如何解决
问题原因
Spring默认的StandardServletMultipartResolver是为multipart/form-data场景设计的,只会把携带Content-Disposition: form-data头的请求部分识别为合法的Multipart对象,不带该头的multipart/related部分会被直接过滤,所以无法通过MultipartHttpServletRequest获取。
解决方案1:使用Apache Commons FileUpload手动解析请求
该方案灵活性最高,不需要修改全局Multipart配置之外的公共逻辑,适配第三方不可修改的请求格式。
步骤1:引入依赖
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.5</version> </dependency>
步骤2:关闭Spring默认Multipart解析
在application.yml中添加配置:
spring: servlet: multipart: enabled: false
步骤3:控制器中编写解析逻辑
@RestController @RequestMapping("/stowrs") public class StowController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @PostMapping(value = "/studies", consumes = MediaType.MULTIPART_RELATED_VALUE) public void store(HttpServletRequest request) throws Exception { boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (!isMultipart) { return; } ServletFileUpload upload = new ServletFileUpload(); // 解析所有请求部分,不会过滤无Content-Disposition的part FileItemIterator iter = upload.getItemIterator(request); while (iter.hasNext()) { FileItemStream item = iter.next(); String contentType = item.getContentType(); try (InputStream inputStream = item.openStream()) { String content = new String(inputStream, StandardCharsets.UTF_8); logger.info("Part Content-Type: {}, Content: {}", contentType, content); // 按业务需求处理对应part即可 } } } }
解决方案2:自定义MultipartResolver全局适配multipart/related
如果项目中还存在其他使用multipart/form-data的接口,更推荐该方案,不需要修改现有接口逻辑即可兼容两种multipart格式。
步骤1:实现自定义解析器
public class MultipartRelatedResolver extends StandardServletMultipartResolver { @Override public boolean isMultipart(HttpServletRequest request) { String contentType = request.getContentType(); // 同时支持form-data和related两种multipart格式 return super.isMultipart(request) || (contentType != null && contentType.startsWith(MediaType.MULTIPART_RELATED_VALUE)); } @Override public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException { MultipartHttpServletRequest multipartRequest = super.resolveMultipart(request); try { Collection<Part> parts = request.getParts(); for (Part part : parts) { String contentDisposition = part.getHeader(HttpHeaders.CONTENT_DISPOSITION); // 把无form-data标识的part手动加入Multipart请求对象 if (contentDisposition == null || !contentDisposition.startsWith("form-data")) { // 可自定义命名规则,比如用索引、contentType作为key String partKey = "part_" + part.getContentType() + "_" + part.hashCode(); ((StandardMultipartHttpServletRequest) multipartRequest).getMultipartFiles().put(partKey, new StandardMultipartFile(part, partKey)); } } } catch (Exception e) { throw new MultipartException("解析multipart/related请求失败", e); } return multipartRequest; } }
步骤2:注册自定义解析器为Bean
@Configuration public class MultipartConfig { @Bean public MultipartResolver multipartResolver() { return new MultipartRelatedResolver(); } }
配置完成后依然可以使用MultipartHttpServletRequest作为控制器参数获取所有请求部分。
内容的提问来源于stack exchange,提问作者Shin DongJin
相关产品推荐
相关产品推荐

