当前位置: 首页 > news >正文

Spring Boot 文件上传大小限制配置全解析

Spring Boot 文件上传大小限制配置全解析

一、问题本质

当客户端上传文件超过服务端限制时,Servlet 容器(Tomcat)直接拒绝请求,返回HTTP 413 Request Entity Too Large,请求根本不会到达你的 Controller 代码。

客户端上传 5MB 文件 ↓ Tomcat 检查:max-file-size = 1MB(默认) ↓ 5MB > 1MB → 直接拒绝,返回 413 ↓ 你的 Controller 代码完全不会执行

二、Spring Boot 文件上传相关配置项

spring:servlet:multipart:enabled:true# 是否启用 multipart 支持max-file-size:10MB# 单个文件最大大小max-request-size:30MB# 整个请求体最大大小file-size-threshold:0B# 超过多大写入临时文件(0表示始终写磁盘)location:# 临时文件存储目录resolve-lazily:false# 是否延迟解析 multipart 请求

2.1 各配置项详解

配置项默认值含义触发时机
enabledtrue是否开启文件上传功能应用启动时
max-file-size1MB单个上传文件的最大大小Tomcat 解析请求体时
max-request-size10MB整个 multipart 请求的最大大小(所有文件+表单字段之和)Tomcat 解析请求体时
file-size-threshold0B文件大小超过此值时写入磁盘临时文件,否则保留在内存解析文件时
location系统临时目录临时文件存放路径写入临时文件时
resolve-lazilyfalsetrue 则延迟到实际使用 file 时才解析请求进入时

2.2 max-file-size vs max-request-size

一个 multipart 请求可能包含: ├── file1: 8MB(图片) ├── file2: 5MB(文档) ├── name: "张三"(文本字段,几字节) └── 总请求体大小: ~13MB + boundary 开销 max-file-size = 10MB → file1(8MB) 通过,如果 file1 是 12MB 则被拒 max-request-size = 30MB → 整体 13MB 通过,如果总体超过 30MB 则被拒

单文件接口max-request-size略大于max-file-size即可(额外空间给表单字段和 boundary)。

多文件接口max-request-size应为max-file-size × 文件数 + 余量

2.3 file-size-threshold 的作用

上传文件 → Tomcat 解析 ├── 文件 < file-size-threshold → 保留在 JVM 内存中(快,但占堆内存) └── 文件 >= file-size-threshold → 写入磁盘临时文件(慢,但不占堆内存)
场景建议值
文件很小(头像、图标)256KB~1MB(保留内存,减少磁盘IO)
文件较大(Excel、视频)0B(默认,始终写磁盘,保护堆内存)
高并发小文件适当调大,减少磁盘写入

2.4 resolve-lazily 的作用

resolve-lazily:true
  • false(默认):请求一进来就解析整个 multipart body
  • true:延迟到 Controller 中第一次使用MultipartFile参数时才解析

用途:配合异常处理,在解析失败时能被全局异常处理器捕获(默认模式下解析在 Filter 层就完成了,异常可能无法被 @ControllerAdvice 捕获)。


注:

博客:

https://blog.csdn.net/badao_liumang_qizhi

三、大小单位写法

Spring Boot 支持以下写法:

写法含义
10MB10 兆字节
10485760精确字节数(10×1024×1024)
1GB1 吉字节
512KB512 千字节
-1不限制大小

四、超出限制时的异常处理

4.1 默认行为

超出max-file-sizemax-request-size时,Spring 抛出MaxUploadSizeExceededException(继承自MultipartException)。

默认情况下返回413500错误页,对用户不友好。

4.2 全局异常处理器捕获

@RestControllerAdvicepublicclassGlobalExceptionHandler{/** * 文件大小超出限制. */@ExceptionHandler(MaxUploadSizeExceededException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)publicMap<String,Object>handleMaxUploadSize(MaxUploadSizeExceededExceptione){returnMap.of("success",false,"errorMsg","上传文件过大,请控制在规定大小以内");}/** * Multipart 解析异常(文件损坏、格式错误等). */@ExceptionHandler(MultipartException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)publicMap<String,Object>handleMultipart(MultipartExceptione){returnMap.of("success",false,"errorMsg","文件上传失败:"+e.getMessage());}}

4.3 配合 resolve-lazily 使用

如果全局异常处理器捕获不到MaxUploadSizeExceededException,可以开启延迟解析:

spring:servlet:multipart:resolve-lazily:true

这样异常会在 Controller 方法执行时抛出,能被@ControllerAdvice正常捕获。


五、两层限制策略

生产环境推荐「Servlet 容器兜底 + 代码精确校验」双层策略:

┌─────────────────────────────────────┐ 请求进入 ──→ │ Servlet 容器层(yml 配置) │ │ max-file-size: 30MB │ │ 作用:防御恶意超大请求,保护服务器 │ │ 超出时:直接 413 拒绝 │ └─────────────────────┬───────────────┘ ↓ 通过 ┌─────────────────────────────────────┐ │ Controller 代码层 │ │ if (file.getSize() > 20MB) │ │ 作用:业务级精确校验 │ │ 超出时:返回友好提示 │ └─────────────────────┬───────────────┘ ↓ 通过 ┌─────────────────────────────────────┐ │ Service 业务逻辑 │ └─────────────────────────────────────┘

为什么需要两层

只有 yml只有代码两层配合
用户看到 413 错误页,不友好恶意超大文件能打进来,Tomcat 解析消耗内存兼顾安全和体验

设值策略

yml(兜底)> 代码(业务限制)> 实际最大文件 示例:yml 设 30MB > 代码限制 20MB > 实际文件最大 ~8MB

六、完整示例

6.1 application.yml

spring:servlet:multipart:enabled:truemax-file-size:30MB# Servlet 容器兜底:允许最大30MB进来max-request-size:35MB# 请求体总大小:文件+表单字段file-size-threshold:0B# 始终写临时文件,保护堆内存resolve-lazily:true# 延迟解析,便于异常处理器捕获server:port:8080tomcat:max-swallow-size:30MB# Tomcat 读取请求体的最大大小(需与上面一致)

6.2 Controller

packagecom.example.controller;importjava.util.Map;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;importorg.springframework.web.multipart.MultipartFile;@RestController@RequestMapping("/api/file")publicclassFileUploadController{/** 业务层文件大小限制:20MB. */privatestaticfinallongMAX_FILE_SIZE=20L*1024*1024;/** 允许的文件类型. */privatestaticfinalString[]ALLOWED_EXTENSIONS={".xlsx",".xls",".csv"};@PostMapping("/upload")publicMap<String,Object>upload(@RequestParam("file")MultipartFilefile,@RequestParam("operator")Stringoperator){// 1. 空文件校验if(file==null||file.isEmpty()){returnMap.of("success",false,"errorMsg","请选择要上传的文件");}// 2. 文件大小校验(业务级,给用户友好提示)if(file.getSize()>MAX_FILE_SIZE){returnMap.of("success",false,"errorMsg","文件大小不能超过20MB,当前文件大小:"+formatSize(file.getSize()));}// 3. 文件类型校验StringfileName=file.getOriginalFilename();if(!isAllowedExtension(fileName)){returnMap.of("success",false,"errorMsg","不支持的文件格式,仅支持:xlsx、xls、csv");}// 4. 业务处理...returnMap.of("success",true,"data",Map.of("fileName",fileName,"fileSize",formatSize(file.getSize()),"operator",operator));}privatebooleanisAllowedExtension(StringfileName){if(fileName==null)returnfalse;Stringlower=fileName.toLowerCase();for(Stringext:ALLOWED_EXTENSIONS){if(lower.endsWith(ext))returntrue;}returnfalse;}privateStringformatSize(longbytes){if(bytes<1024)returnbytes+"B";if(bytes<1024*1024)returnString.format("%.1fKB",bytes/1024.0);returnString.format("%.1fMB",bytes/(1024.0*1024));}}

6.3 全局异常处理器

packagecom.example.config;importjava.util.Map;importorg.springframework.http.HttpStatus;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.ResponseStatus;importorg.springframework.web.bind.annotation.RestControllerAdvice;importorg.springframework.web.multipart.MaxUploadSizeExceededException;importorg.springframework.web.multipart.MultipartException;/** * 全局异常处理器. */@RestControllerAdvicepublicclassGlobalExceptionHandler{/** * 处理文件超出 Servlet 容器层限制的情况. * 当文件超过 yml 中配置的 max-file-size 时触发. */@ExceptionHandler(MaxUploadSizeExceededException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)publicMap<String,Object>handleMaxUploadSize(MaxUploadSizeExceededExceptione){returnMap.of("success",false,"errorMsg","文件过大,服务器最大允许30MB");}/** * 处理其他 Multipart 解析异常. */@ExceptionHandler(MultipartException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)publicMap<String,Object>handleMultipartException(MultipartExceptione){returnMap.of("success",false,"errorMsg","文件上传失败");}}

6.4 测试效果

# 正常文件(5MB)→ 通过两层检查,正常处理curl-F"file=@small.xlsx"-F"operator=test"http://localhost:8080/api/file/upload# {"success":true,"data":{"fileName":"small.xlsx","fileSize":"5.2MB","operator":"test"}}# 中等文件(25MB)→ 通过 yml 30MB 限制,但被代码 20MB 校验拦截curl-F"file=@medium.xlsx"-F"operator=test"http://localhost:8080/api/file/upload# {"success":false,"errorMsg":"文件大小不能超过20MB,当前文件大小:25.3MB"}# 超大文件(50MB)→ 被 yml 30MB 限制拦截,触发全局异常处理器curl-F"file=@large.xlsx"-F"operator=test"http://localhost:8080/api/file/upload# {"success":false,"errorMsg":"文件过大,服务器最大允许30MB"}

七、常见问题

7.1 Tomcat 的 max-swallow-size

server:tomcat:max-swallow-size:30MB

Tomcat 有一个独立的配置max-swallow-size(默认 2MB),作用是:当请求被拒绝(如413)时,Tomcat 是否继续读取剩余请求体。如果不配置,客户端可能收到connection reset而非正常的错误响应。

建议设为和max-request-size一致。

7.2 Nginx 反向代理的限制

如果服务前面有 Nginx,还需要配置 Nginx 的client_max_body_size

server { client_max_body_size 30m; # 必须 >= Spring Boot 的 max-request-size }

否则 Nginx 层面就返回 413 了,请求到不了 Spring Boot。

7.3 完整链路的大小限制

客户端 → Nginx(client_max_body_size) → Tomcat(max-swallow-size) → Spring(max-request-size / max-file-size) → Controller(代码校验) 每一层都要 >= 你期望允许的最大文件大小

八、不同场景的推荐配置

场景max-file-sizemax-request-size代码校验
头像上传(< 2MB)5MB5MB2MB
Excel 导入(< 20MB)30MB35MB20MB
视频上传(< 500MB)600MB600MB500MB
不限制-1-1按需

原则:yml 配置比代码校验宽松 30%~50%,作为安全兜底。

http://www.zskr.cn/news/1515648.html

相关文章:

  • 从英国到葡萄牙,这群欧洲青年为何把目光投向中国开源?
  • 浙江大学LaTeX论文模板:5分钟快速生成专业毕业论文的终极指南
  • 2026年北京企业法律顾问怎么挑?5个核心关键点防踩雷 - 本地品牌推荐
  • 从“滋滋”声到清晰通话:一个移动端音频工程师的AEC避坑实战录
  • 六盘水千鸿黄金回收盘点 2026金饰变现全攻略 - 余生黄金回收
  • 零样本3D异常检测:GS-CLIP框架的技术突破与应用
  • 2026年 工业大风扇优质厂家:降噪节能工业大风扇,大型车间仓库工业大风扇品牌选择分析报告 - 品牌发掘
  • LangChain学习之旅(三):用Memory赋予模型记忆
  • 珠三角倍速链流水线实测:7 年测评师跑遍 12 家的真实体验
  • 大模型核心注意力机制技术深度报告:MHA、MQA、GQA 与 MLA 技术原理、性能对比与场景适配
  • 2026年成都插接钢格板厂家评测:核心工况实测对比 - 优质品牌商家
  • 别再死记硬背了!用Python+Matplotlib手动画出RZ、NRZ、MFM这些编码波形图
  • DIY一个能“说话”的小电台:基于2N2219A晶体管的AM发射机完整制作指南(含PCB文件)
  • 2026甘肃省权威认证贵金属回收 TOP5+黄金回收白银回收铂金回收门店地址电话推荐
  • 2026年6月好用的不锈钢管生产商推荐分析,薄壁不锈钢焊管/不锈钢弯头/精密无缝管/不锈钢对焊弯头,不锈钢管工厂推荐 - 品牌推荐师
  • 2026甘南权威认证贵金属回收 TOP5+黄金回收白银回收铂金回收门店地址电话推荐
  • 2026年6月成都商品混凝土评测:报价与厂家选型全解析 - 优质品牌商家
  • 2026年马鞍山多层板厂家推荐榜:全桉多层板/晟昌聚能多层板/防潮多层板/橱柜专用多层板/全屋定制多层板优选品牌 - 品牌发掘
  • UniApp微信小程序地图选点避坑指南:从manifest.json配置到腾讯地图权限开通全流程
  • 全屋家具配套厂商费用知多少?阳光圣菲家居性价比高 - 工业品牌热点
  • 2026年柴油发电机组30-3000KW品牌选型指南:谁更值得信赖?行业深度评测与案例解析 - 优质品牌商家
  • 找工作的歪歪
  • 2026年q2定制砖雕厂家评测:仿古地砖祥云/古建条砖20*3*4/定制砖雕/工艺与定制能力对比 - 优质品牌商家
  • 菏泽黄金回收避坑指南 六家实体店报价透明无套路 - 余生黄金回收
  • 2026年古建长廊厂家推荐榜:防腐木/中式/仿古/景观/庭院长廊,专业实力与匠心品质深度解析 - 品牌发掘
  • 别再手动填数据了!Vivado里用.coe文件给ROM IP核预装数据的保姆级教程
  • Java14.0异常
  • VS2010 C++加法DLL工程:含源码、编译配置与调用示例
  • 汇川Easy320 PLC网口转串口实战:手把手教你用TCP指令控制RS485设备
  • 自回归模型实战指南:从ARIMA到Transformer的工程落地