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:truefalse默认请求一进来就解析整个 multipart bodytrue延迟到 Controller 中第一次使用MultipartFile参数时才解析用途配合异常处理在解析失败时能被全局异常处理器捕获默认模式下解析在 Filter 层就完成了异常可能无法被 ControllerAdvice 捕获。注博客https://blog.csdn.net/badao_liumang_qizhi三、大小单位写法Spring Boot 支持以下写法写法含义10MB10 兆字节10485760精确字节数10×1024×10241GB1 吉字节512KB512 千字节-1不限制大小四、超出限制时的异常处理4.1 默认行为超出max-file-size或max-request-size时Spring 抛出MaxUploadSizeExceededException继承自MultipartException。默认情况下返回413或500错误页对用户不友好。4.2 全局异常处理器捕获RestControllerAdvicepublicclassGlobalExceptionHandler{/** * 文件大小超出限制. */ExceptionHandler(MaxUploadSizeExceededException.class)ResponseStatus(HttpStatus.BAD_REQUEST)publicMapString,ObjecthandleMaxUploadSize(MaxUploadSizeExceededExceptione){returnMap.of(success,false,errorMsg,上传文件过大请控制在规定大小以内);}/** * Multipart 解析异常文件损坏、格式错误等. */ExceptionHandler(MultipartException.class)ResponseStatus(HttpStatus.BAD_REQUEST)publicMapString,ObjecthandleMultipart(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.ymlspring: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 Controllerpackagecom.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;RestControllerRequestMapping(/api/file)publicclassFileUploadController{/** 业务层文件大小限制20MB. */privatestaticfinallongMAX_FILE_SIZE20L*1024*1024;/** 允许的文件类型. */privatestaticfinalString[]ALLOWED_EXTENSIONS{.xlsx,.xls,.csv};PostMapping(/upload)publicMapString,Objectupload(RequestParam(file)MultipartFilefile,RequestParam(operator)Stringoperator){// 1. 空文件校验if(filenull||file.isEmpty()){returnMap.of(success,false,errorMsg,请选择要上传的文件);}// 2. 文件大小校验业务级给用户友好提示if(file.getSize()MAX_FILE_SIZE){returnMap.of(success,false,errorMsg,文件大小不能超过20MB当前文件大小formatSize(file.getSize()));}// 3. 文件类型校验StringfileNamefile.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(fileNamenull)returnfalse;StringlowerfileName.toLowerCase();for(Stringext:ALLOWED_EXTENSIONS){if(lower.endsWith(ext))returntrue;}returnfalse;}privateStringformatSize(longbytes){if(bytes1024)returnbytesB;if(bytes1024*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)publicMapString,ObjecthandleMaxUploadSize(MaxUploadSizeExceededExceptione){returnMap.of(success,false,errorMsg,文件过大服务器最大允许30MB);}/** * 处理其他 Multipart 解析异常. */ExceptionHandler(MultipartException.class)ResponseStatus(HttpStatus.BAD_REQUEST)publicMapString,ObjecthandleMultipartException(MultipartExceptione){returnMap.of(success,false,errorMsg,文件上传失败);}}6.4 测试效果# 正常文件5MB→ 通过两层检查正常处理curl-Ffilesmall.xlsx-Foperatortesthttp://localhost:8080/api/file/upload# {success:true,data:{fileName:small.xlsx,fileSize:5.2MB,operator:test}}# 中等文件25MB→ 通过 yml 30MB 限制但被代码 20MB 校验拦截curl-Ffilemedium.xlsx-Foperatortesthttp://localhost:8080/api/file/upload# {success:false,errorMsg:文件大小不能超过20MB当前文件大小25.3MB}# 超大文件50MB→ 被 yml 30MB 限制拦截触发全局异常处理器curl-Ffilelarge.xlsx-Foperatortesthttp://localhost:8080/api/file/upload# {success:false,errorMsg:文件过大服务器最大允许30MB}七、常见问题7.1 Tomcat 的 max-swallow-sizeserver:tomcat:max-swallow-size:30MBTomcat 有一个独立的配置max-swallow-size默认 2MB作用是当请求被拒绝如413时Tomcat 是否继续读取剩余请求体。如果不配置客户端可能收到connection reset而非正常的错误响应。建议设为和max-request-size一致。7.2 Nginx 反向代理的限制如果服务前面有 Nginx还需要配置 Nginx 的client_max_body_sizeserver { 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代码校验头像上传 2MB5MB5MB2MBExcel 导入 20MB30MB35MB20MB视频上传 500MB600MB600MB500MB不限制-1-1按需原则yml 配置比代码校验宽松 30%~50%作为安全兜底。
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:truefalse默认请求一进来就解析整个 multipart bodytrue延迟到 Controller 中第一次使用MultipartFile参数时才解析用途配合异常处理在解析失败时能被全局异常处理器捕获默认模式下解析在 Filter 层就完成了异常可能无法被 ControllerAdvice 捕获。注博客https://blog.csdn.net/badao_liumang_qizhi三、大小单位写法Spring Boot 支持以下写法写法含义10MB10 兆字节10485760精确字节数10×1024×10241GB1 吉字节512KB512 千字节-1不限制大小四、超出限制时的异常处理4.1 默认行为超出max-file-size或max-request-size时Spring 抛出MaxUploadSizeExceededException继承自MultipartException。默认情况下返回413或500错误页对用户不友好。4.2 全局异常处理器捕获RestControllerAdvicepublicclassGlobalExceptionHandler{/** * 文件大小超出限制. */ExceptionHandler(MaxUploadSizeExceededException.class)ResponseStatus(HttpStatus.BAD_REQUEST)publicMapString,ObjecthandleMaxUploadSize(MaxUploadSizeExceededExceptione){returnMap.of(success,false,errorMsg,上传文件过大请控制在规定大小以内);}/** * Multipart 解析异常文件损坏、格式错误等. */ExceptionHandler(MultipartException.class)ResponseStatus(HttpStatus.BAD_REQUEST)publicMapString,ObjecthandleMultipart(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.ymlspring: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 Controllerpackagecom.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;RestControllerRequestMapping(/api/file)publicclassFileUploadController{/** 业务层文件大小限制20MB. */privatestaticfinallongMAX_FILE_SIZE20L*1024*1024;/** 允许的文件类型. */privatestaticfinalString[]ALLOWED_EXTENSIONS{.xlsx,.xls,.csv};PostMapping(/upload)publicMapString,Objectupload(RequestParam(file)MultipartFilefile,RequestParam(operator)Stringoperator){// 1. 空文件校验if(filenull||file.isEmpty()){returnMap.of(success,false,errorMsg,请选择要上传的文件);}// 2. 文件大小校验业务级给用户友好提示if(file.getSize()MAX_FILE_SIZE){returnMap.of(success,false,errorMsg,文件大小不能超过20MB当前文件大小formatSize(file.getSize()));}// 3. 文件类型校验StringfileNamefile.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(fileNamenull)returnfalse;StringlowerfileName.toLowerCase();for(Stringext:ALLOWED_EXTENSIONS){if(lower.endsWith(ext))returntrue;}returnfalse;}privateStringformatSize(longbytes){if(bytes1024)returnbytesB;if(bytes1024*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)publicMapString,ObjecthandleMaxUploadSize(MaxUploadSizeExceededExceptione){returnMap.of(success,false,errorMsg,文件过大服务器最大允许30MB);}/** * 处理其他 Multipart 解析异常. */ExceptionHandler(MultipartException.class)ResponseStatus(HttpStatus.BAD_REQUEST)publicMapString,ObjecthandleMultipartException(MultipartExceptione){returnMap.of(success,false,errorMsg,文件上传失败);}}6.4 测试效果# 正常文件5MB→ 通过两层检查正常处理curl-Ffilesmall.xlsx-Foperatortesthttp://localhost:8080/api/file/upload# {success:true,data:{fileName:small.xlsx,fileSize:5.2MB,operator:test}}# 中等文件25MB→ 通过 yml 30MB 限制但被代码 20MB 校验拦截curl-Ffilemedium.xlsx-Foperatortesthttp://localhost:8080/api/file/upload# {success:false,errorMsg:文件大小不能超过20MB当前文件大小25.3MB}# 超大文件50MB→ 被 yml 30MB 限制拦截触发全局异常处理器curl-Ffilelarge.xlsx-Foperatortesthttp://localhost:8080/api/file/upload# {success:false,errorMsg:文件过大服务器最大允许30MB}七、常见问题7.1 Tomcat 的 max-swallow-sizeserver:tomcat:max-swallow-size:30MBTomcat 有一个独立的配置max-swallow-size默认 2MB作用是当请求被拒绝如413时Tomcat 是否继续读取剩余请求体。如果不配置客户端可能收到connection reset而非正常的错误响应。建议设为和max-request-size一致。7.2 Nginx 反向代理的限制如果服务前面有 Nginx还需要配置 Nginx 的client_max_body_sizeserver { 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代码校验头像上传 2MB5MB5MB2MBExcel 导入 20MB30MB35MB20MB视频上传 500MB600MB600MB500MB不限制-1-1按需原则yml 配置比代码校验宽松 30%~50%作为安全兜底。