如何让Spring在文件上传达到指定大小后立即中断并抛异常?
解决Spring文件上传超限制后才抛异常的问题
这个问题我之前也踩过坑!根源在于Spring默认的文件上传解析器逻辑:不管是CommonsMultipartResolver还是默认实现,都是先把整个文件完整写入临时存储,之后才会校验文件大小——这就是为啥你设了7MB限制,却要等文件全传完才会抛出MaxUploadSizeExceededException的原因。
要实现达到大小限制时立刻中断上传,给你两种实用方案:
方案一:基于commons-fileupload自定义进度监听(适合老项目)
如果你的项目还在依赖commons-fileupload包,那可以通过自定义进度监听器实时监控上传进度,一旦超限制就主动掐断请求:
- 先写一个进度监听器,实时检查已上传字节数:
import org.apache.commons.fileupload.ProgressListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class SizeLimitProgressListener implements ProgressListener { private final long maxAllowedSize; private final HttpServletRequest request; private final HttpServletResponse response; public SizeLimitProgressListener(long maxSize, HttpServletRequest req, HttpServletResponse resp) { this.maxAllowedSize = maxSize; this.request = req; this.response = resp; } @Override public void update(long bytesRead, long contentLength, int items) { // 每上传一点就检查一次,超过限制直接中断 if (bytesRead > maxAllowedSize) { try { request.getInputStream().close(); response.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, "文件大小超出7MB限制"); } catch (IOException e) { // 这里可以根据业务做异常日志记录 e.printStackTrace(); } } } }
- 自定义MultipartResolver,把监听器注入进去:
import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import javax.servlet.http.HttpServletRequest; public class CustomMultipartResolver extends CommonsMultipartResolver { private long maxUploadSize; @Override public void setMaxUploadSize(long maxUploadSize) { super.setMaxUploadSize(maxUploadSize); this.maxUploadSize = maxUploadSize; } @Override protected ServletFileUpload newFileUpload(FileItemFactory fileItemFactory) { ServletFileUpload upload = new ServletFileUpload(fileItemFactory); upload.setSizeMax(this.maxUploadSize); return upload; } @Override protected ServletFileUpload prepareFileUpload(String encoding) { ServletFileUpload upload = (ServletFileUpload) super.prepareFileUpload(encoding); // 给上传器绑定自定义监听器 upload.setProgressListener(new SizeLimitProgressListener(this.maxUploadSize, getRequest(), getResponse())); return upload; } }
- 最后在
dispatcher-servlet.xml里替换掉默认的Resolver:
<bean id="multipartResolver" class="com.yourproject.utils.CustomMultipartResolver"> <property name="maxUploadSize" value="7340032"/> <!-- 7MB转换成字节:7*1024*1024=7340032 --> <property name="maxInMemorySize" value="4096"/> <!-- 小于4KB的文件存在内存里 --> </bean>
方案二:用Servlet 3.0+的StandardServletMultipartResolver(推荐)
如果你的项目是基于Servlet 3.0及以上版本,强烈推荐这个方案——不需要写任何自定义类,配置就能搞定,而且是Servlet容器层面实时校验,超限制立刻中断。
- 先在
dispatcher-servlet.xml里配置标准Resolver:
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
- 然后在
web.xml里给DispatcherServlet加上传参数配置:
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/dispatcher-servlet.xml</param-value> </init-param> <!-- 重点是这个multipart-config块 --> <multipart-config> <max-file-size>7340032</max-file-size> <!-- 单个文件最大7MB --> <max-request-size>7340032</max-request-size> <!-- 整个请求的总大小限制 --> <file-size-threshold>4096</file-size-threshold> <!-- 超过4KB就写入临时文件 --> </multipart-config> <load-on-startup>1</load-on-startup> </servlet>
要是你用的是Java Config来配置Servlet,那可以这么写:
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import javax.servlet.MultipartConfigElement; import javax.servlet.ServletRegistration; public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { // 省略其他重写的方法(比如getRootConfigClasses、getServletConfigClasses) @Override protected void customizeRegistration(ServletRegistration.Dynamic registration) { // 构建文件上传配置 MultipartConfigElement multipartConfig = new MultipartConfigElement( null, // 临时文件存储路径,默认用容器的临时目录 7340032, // 单个文件最大大小 7340032, // 请求总大小 4096 // 内存存储阈值 ); registration.setMultipartConfig(multipartConfig); } }
配置完之后,当用户上传的文件超过7MB时,Servlet容器会在上传过程中直接中断请求,返回413 Request Entity Too Large,不用等文件传完。最后记得在全局异常处理器里捕获相关异常,给前端返回友好的提示哦~
内容的提问来源于stack exchange,提问作者niilzon
相关产品推荐
相关产品推荐

