Spring Boot中如何将HttpServletRequest转为MultipartHttpServletRequest
解决Spring Security包装请求导致MultipartHttpServletRequest转换失败的问题
问题原因
Spring Security会将原始请求包装为Servlet3SecurityContextHolderAwareRequestWrapper类以集成安全上下文。此时直接对这个包装类执行instanceof判断或强转为MultipartHttpServletRequest会抛出类型转换异常——因为包装类并非MultipartHttpServletRequest的子类,必须先拿到被包装的原始请求对象。
解决步骤
1. 编写工具方法剥离请求包装
通过循环获取被层层包装的原始请求,直到拿到最底层的真实请求:
private HttpServletRequest getOriginalRequest(HttpServletRequest request) { while (request instanceof ServletRequestWrapper) { ServletRequest wrappedRequest = ((ServletRequestWrapper) request).getRequest(); // 防止极端情况下的无限循环 if (wrappedRequest == request) { break; } request = (HttpServletRequest) wrappedRequest; } return request; }
2. 在过滤器中处理文件上传请求
在过滤器的doFilter方法中,先判断请求类型,再剥离包装获取原始请求,最后提取文件元数据:
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; // 先判断是否为文件上传请求 boolean isMultipartRequest = request.getContentType() != null && request.getContentType().startsWith("multipart/form-data"); if (isMultipartRequest) { // 获取原始请求 HttpServletRequest originalRequest = getOriginalRequest(request); MultipartHttpServletRequest multipartRequest = null; // 尝试直接转换原始请求 if (originalRequest instanceof MultipartHttpServletRequest) { multipartRequest = (MultipartHttpServletRequest) originalRequest; } else { // 用Spring工具类尝试获取Multipart请求 multipartRequest = RequestContextUtils.getMultipartHttpServletRequest(originalRequest); } if (multipartRequest != null) { // 仅提取文件元数据,不读取文件内容 for (String fileParamName : multipartRequest.getFileNames()) { MultipartFile file = multipartRequest.getFile(fileParamName); if (file != null) { String fileName = file.getOriginalFilename(); long fileSize = file.getSize(); String contentType = file.getContentType(); // 将元数据存入日志数据库的逻辑 // ... } } } } else { // 处理非文件上传请求的日志记录逻辑 // ... } // 继续执行过滤器链 filterChain.doFilter(servletRequest, servletResponse); }
注意事项
- 避免读取文件内容:只调用
getOriginalFilename()、getSize()、getContentType()等获取元数据的方法,不要使用getBytes()、transferTo()等读取文件内容的方法,防止占用过多内存和影响接口性能。 - 过滤器顺序:如果你的过滤器配置在Spring Security过滤器之前,原始请求还未被包装,可直接判断类型;若在之后,则必须执行剥离包装的步骤。
内容的提问来源于stack exchange,提问作者Basti797
相关产品推荐
相关产品推荐

