You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring自定义DispatcherServlet记录multipart请求报错如何解决

问题原因

核心错误有三点:

  • 逻辑错误:判断为multipart请求时你主动跳过了super.doDispatch(request, response)调用,导致请求没有被Spring MVC分发到对应控制器,自然没有响应生成,后续updateResponse操作必然失败
  • 配置缺失:你自定义注册的DispatcherServlet没有绑定Spring Boot自动生成的multipart配置,所以解析multipart请求时会抛出Unable to process parts as no multi-part configuration has been provided错误
  • 请求包装错误:你直接用ContentCachingRequestWrapper包装了原始multipart请求,提前消费了请求输入流,导致Spring的MultipartResolver无法正常解析文件参数
解决方案

分两步修改代码:

1. 修正Servlet注册配置,绑定multipart配置

修改你的LogsConfig类,注入Spring Boot自动配置的MultipartConfigElement并绑定到ServletRegistrationBean:

import com.altair.autoTester.logs.LoggableDispatcherServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.MultipartConfigElement;

@Configuration
public class LogsConfig {

    // 注入Spring Boot自动配置好的multipart参数
    @Autowired
    private MultipartConfigElement multipartConfig;

    @Bean
    public ServletRegistrationBean dispatcherRegistration() {
        ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet());
        // 绑定multipart配置到自定义DispatcherServlet
        registration.setMultipartConfig(multipartConfig);
        return registration;
    }

    @Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    public DispatcherServlet dispatcherServlet() {
        return new LoggableDispatcherServlet();
    }
}

2. 修正LoggableDispatcherServlet的分发逻辑

删除跳过super.doDispatch的逻辑,multipart请求不做RequestWrapper包装,避免破坏请求解析:

@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    boolean isMultipart = request.getContentType() != null && request.getContentType().toLowerCase().contains("multipart/form-data");
    HttpServletRequest processedRequest = request;
    // 非multipart请求才用ContentCachingRequestWrapper包装,避免干扰文件解析
    if (!isMultipart && !(request instanceof ContentCachingRequestWrapper)) {
        processedRequest = new ContentCachingRequestWrapper(request);
    }
    if (!(response instanceof ContentCachingResponseWrapper)) {
        response = new ContentCachingResponseWrapper(response);
    }
    HandlerExecutionChain handler = getHandler(processedRequest);
    try {
        // 所有类型的请求都必须调用父类分发逻辑才能进入控制器
        super.doDispatch(processedRequest, response);
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
        // 务必抛出异常,否则Spring全局异常处理器不会生效
        throw e;
    } finally {
        // 统一执行日志和响应更新逻辑
        log(processedRequest, response, handler);
        updateResponse(response);
    }
}
补充说明
  • multipart请求的普通表单参数可以直接通过request.getParameterMap()获取,不需要读取请求体打日志
  • 不建议读取上传的二进制文件内容打日志,会额外占用大量内存和IO资源
  • 如果你确实需要记录上传文件的元信息(如文件名、大小),可以从解析后的MultipartHttpServletRequest中直接获取,不需要操作原始请求流

内容的提问来源于stack exchange,提问作者Gilad Dahan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 12:57:01