当前位置: 首页 > 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.jsqmd.com/news/1003862/

相关文章:

  • 从英国到葡萄牙,这群欧洲青年为何把目光投向中国开源?
  • 寄行李大件什么物流最省钱?用“寄半折”比价立省一半 - 快递物流资讯
  • 2026甘孜州权威认证贵金属回收 TOP5+黄金回收白银回收铂金回收门店地址电话推荐
  • Logisim 2.7.1 手把手:从零搭建一个支持13种运算的32位MIPS ALU(附完整电路图)
  • 2026年北京企业法律顾问怎么挑?5个核心关键点防踩雷 - 本地品牌推荐
  • STM32CubeMX配置I2C驱动AT24C64 EEPROM,手把手教你搞定用户设置数据存储(附完整工程代码)
  • 2026年q2正规青年旅行社官网品牌技术维度解析:美国旅游/318川藏线自驾游/中国青年旅行社官网/优选推荐 - 优质品牌商家
  • 2026年新中式门楼设计施工服务商评测:五大品牌对比 - 优质品牌商家
  • 保姆级教程:用ADB命令备份与删除长安UNI-V车机自带软件(附完整命令清单)
  • Windows电脑频繁弹广告怎么彻底清除?从定位来源到卸载残留的完整方法
  • 从“滋滋”声到清晰通话:一个移动端音频工程师的AEC避坑实战录
  • 2026年国内篮球架选购全攻略:从材料工艺到工程案例的行业深度调研 - 优质品牌商家
  • 长沙鑫合诚新能源物流车联系电话多少?快速获取 - 工业品牌热点
  • 别再手动填数据了!Vivado 2023.2 中一键生成 .coe 文件并配置 ROM IP 核的保姆级教程
  • 工业吸尘器怎么选?类型、功率、过滤与产区厂商全解析
  • 零样本3D异常检测:GS-CLIP框架的技术突破与应用
  • 临汾余生黄金回收实测 2026六家门店价格对比 - 余生黄金回收
  • Arduino UNO连接WS2812B全彩LED,比板载RGB灯强在哪?手把手配置指南
  • 六盘水千鸿黄金回收盘点 2026金饰变现全攻略 - 余生黄金回收
  • Xilinx FPGA平台SRIO环回通信实测工程包(含源码、bit文件与操作指南)
  • 2026实力之选:广东单头加热管厂家如何应对全场景定制挑战? - 品牌发掘
  • C盘快满了该怎么一步步清理?6个操作步骤从根源腾空间
  • 2026年 工业大风扇优质厂家:降噪节能工业大风扇,大型车间仓库工业大风扇品牌选择分析报告 - 品牌发掘
  • agno v2.6.13 最新版本发布:AgentOS、Workflows、MCPTools、JSON Schema 等多项更新全面解析
  • LangChain学习之旅(三):用Memory赋予模型记忆
  • AI 技术日报 - 2026-06-13
  • 珠三角倍速链流水线实测:7 年测评师跑遍 12 家的真实体验
  • 陇南光纤抢修技术全解析:专业标准与本地服务推荐 - 优质品牌商家
  • Vue3+Vite4实战:手把手教你用Easy Process仿钉钉搭建OA审批流(附完整源码)
  • Python原生OLAP BI平台:atoti实战指南