1. 为什么SpringBoot默认限制文件上传大小?
第一次用SpringBoot做文件上传功能时,我兴冲冲地写好了接口,测试时上传了个2MB的图片,结果页面直接报错。控制台里赫然写着"The field file exceeds its maximum permitted size of 1048576 bytes"。当时我就纳闷了:为什么会有这种限制?后来查源码才发现,这是SpringBoot的自我保护机制。
在MultipartProperties这个配置类里,明确定义了两个关键参数:
private DataSize maxFileSize = DataSize.ofMegabytes(1L); // 单个文件默认1MB private DataSize maxRequestSize = DataSize.ofMegabytes(10L); // 请求总量默认10MB这种设计其实很合理。想象一下,如果没有限制,用户突然上传个10GB的视频,服务器可能直接内存溢出。早期版本甚至出现过通过文件上传进行DDoS攻击的案例。不过1MB确实有点保守,现在手机随便拍张照片都超过这个大小了。
2. 配置文件修改的三种姿势
2.1 application.properties配置法
最直接的修改方式就是在配置文件中覆盖默认值。如果你用的是properties格式,可以这样写:
spring.servlet.multipart.max-file-size=10MB spring.servlet.multipart.max-request-size=50MB这里有个坑要注意:值后面的单位不能省略。曾经有同事写成max-file-size=1024,结果系统按字节处理,实际限制变成1KB,导致用户连头像都传不上去。
2.2 application.yml配置法
我个人更推荐yml格式,层次结构更清晰:
spring: servlet: multipart: max-file-size: 20MB max-request-size: 100MB enabled: true注意缩进必须用空格,不能用Tab键。有一次我复制网上的配置,因为缩进问题导致配置没生效,排查了半天才发现是格式问题。
2.3 Java代码硬编码配置
虽然不推荐,但在某些特殊场景下可能需要动态调整限制大小。可以在@Configuration类里这样配置:
@Bean public MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); factory.setMaxFileSize(DataSize.ofMegabytes(50)); factory.setMaxRequestSize(DataSize.ofGigabytes(1)); return factory.createMultipartConfig(); }3. 生产环境中的实战经验
3.1 合理设置大小限制
千万别无脑设置成超大值。根据我的经验:
- 用户头像:建议2-5MB
- 商品图片:5-10MB
- 文档附件:10-50MB
- 视频文件:单独做断点续传
曾经有个电商项目,我们把限制设为500MB,结果有用户真上传了400多MB的PSD源文件,把存储空间都撑爆了。
3.2 前端也要做验证
即使后端改了配置,前端仍然需要做文件大小校验。双重验证更保险:
// 前端验证示例 function checkFile(file) { const maxSize = 10 * 1024 * 1024; // 10MB if(file.size > maxSize) { alert('文件不能超过10MB'); return false; } return true; }3.3 监控与告警机制
建议在网关层或拦截器里添加监控:
@PostMapping("/upload") public ResponseEntity upload(@RequestParam("file") MultipartFile file) { if(file.getSize() > 5 * 1024 * 1024) { metrics.increment("largeFile.upload"); } // ...处理逻辑 }我们团队曾用Prometheus+Granfa搭建了文件上传监控看板,当大文件上传频率异常时能及时收到告警。
4. 那些年踩过的坑
4.1 单位大小写问题
有次配置写成max-file-size=10mb,结果不生效。后来发现必须用大写MB:
# 正确写法 max-file-size: 10MB # 错误写法(不报错但无效) max-file-size: 10mb4.2 多模块配置冲突
在SpringCloud项目中,网关和微服务都可能配置上传限制。我们遇到过网关设了100MB,业务服务却是10MB的情况。正确的做法是保持配置一致,或者在网关做文件转发。
4.3 内存与临时文件
超过spring.servlet.multipart.file-size-threshold大小的文件会被写入临时目录。如果没设置location,系统临时目录可能会满:
spring: servlet: multipart: location: /data/tmp file-size-threshold: 5MB曾经有台服务器因为没设这个,临时目录把磁盘占满导致系统崩溃。现在我都习惯在启动脚本里主动清理临时文件。
5. 高级配置技巧
5.1 按接口动态调整
通过HandlerInterceptor可以针对特定接口设置不同限制:
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { if(request.getRequestURI().contains("/video/upload")) { MultipartConfigElement config = new MultipartConfigFactory() .setMaxFileSize("500MB") .createMultipartConfig(); request.setAttribute("multipartConfig", config); } }5.2 自定义错误处理
默认的错误信息对用户不友好,可以自定义异常处理:
@ControllerAdvice public class FileUploadExceptionHandler { @ExceptionHandler(MaxUploadSizeExceededException.class) public ResponseEntity handleMaxSizeException() { return ResponseEntity.badRequest().body("文件大小超过限制"); } }5.3 测试验证方法
建议在单元测试中加入边界测试:
@Test public void testFileSizeLimit() throws Exception { MockMultipartFile largeFile = new MockMultipartFile( "file", "test.jpg", "image/jpeg", new byte[11 * 1024 * 1024]); // 11MB mockMvc.perform(multipart("/upload").file(largeFile)) .andExpect(status().isBadRequest()); }