Spring Boot 文件上传配置:这几个 multipart 参数搞明白就差不多了

最近在给项目加文件上传,顺便把 Spring Boot 里 multipart 这块的配置重新过了一遍。其实核心参数就几个,但真出问题往往就卡在某个值没配对,尤其线上环境。

写下来留个记录。

配置写在 application.properties 或者 application.yml 都行,看项目习惯。properties 格式:

spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=100MB
spring.servlet.multipart.file-size-threshold=1MB
spring.servlet.multipart.location=/tmp/uploads

yml 写法:

spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 100MB
      file-size-threshold: 1MB
      location: /tmp/uploads

max-file-size 控制单个上传文件的最大大小,默认是无限制。这个不建议放开,不然一个超大文件能把请求线程一直占着,内存也可能被打满。max-request-size 是整个请求的大小,包括多个文件和表单其他字段。有人只配了 max-file-size,结果传多个文件时还是报超过限制,问题基本就出在 max-request-size 没跟着调大。比如单文件 10MB,一个请求传 3 个文件再带点别的字段,整个请求体可能就 31MB,max-request-size 如果还是默认无限制倒没事,但一旦你设了个小于这个值的数,就会报错。

file-size-threshold 这个参数默认是 0,意思是所有上传文件直接写磁盘,不经过内存暂存。如果希望小一点的文件先放内存、超过阈值再写磁盘,可以设一个值,比如 2KB 或 4KB。

但说实话,现在磁盘 IO 没以前那么敏感,多数场景保持默认也没问题,除非你服务器磁盘很慢,小文件频繁读写反而拉低性能。

location 指定临时文件的存放目录。Servlet 3.0 之后这个参数还挺重要,不指定的话有些容器会写到系统临时目录,但那个目录在某些部署环境里权限不可控,容易出权限异常。建议显式配一个应用有读写权限的绝对路径,并且提前把目录建好。

容器化部署的时候尤其注意,镜像里 /tmp 可能没问题,但你自定义的目录如果没在 Dockerfile 里创建,运行时就会报错。

如果不想用配置文件,也可以用 Java Config 动态设置。代码大概这样:

import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.MultipartConfigElement;

@Configuration
public class WebConfig {
    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setMaxFileSize("10MB");
        factory.setMaxRequestSize("100MB");
        factory.setLocation("/tmp/uploads");
        return factory.createMultipartConfig();
    }
}

这种方式适合路径需要从配置中心或环境变量里拿的场景,纯写死在 properties 里也够用。控制器里接收文件用 MultipartFile,常规写法:

import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;

@RestController
public class UploadController {
    @PostMapping("/upload")
    public String handleFileUpload(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return "请选择文件";
        }
        try {
            File dest = new File("/tmp/uploads/" + file.getOriginalFilename());
            file.transferTo(dest);
            return "上传成功: " + file.getOriginalFilename();
        } catch (IOException e) {
            e.printStackTrace();
            return "上传失败";
        }
    }
}

注意 transferTo 不会自动创建目标目录,如果 /tmp/uploads 不存在,会抛 IOException。提前建目录或者用 Files.createDirectories 更稳妥。

lcjmSSL将SSL证书管理转变为自动化流程。自动验证(HTTP/DNS代理)、自动部署、自动提醒、自动重申四大环节环环相扣,从此不再为证书过期担忧,安全始终在线。

还有,file.getOriginalFilename() 直接拼路径有路径穿越风险,生产上别这么干,要么重命名,要么过滤掉 ../ 之类的字符。

多文件上传的时候,表单加 multiple 属性,控制器参数用数组:

@PostMapping("/multi-upload")
public String handleMultiUpload(@RequestParam("files") MultipartFile[] files) {
    for (MultipartFile file : files) {
        if (!file.isEmpty()) {
            // 逐个处理
        }
    }
    return "上传完成";
}

这里有个细节,如果前端一个文件都没选,有的浏览器会发一个空文件名的 part,file.isEmpty() 能拦住,不用额外判断文件名是否为空。

生产环境建议还是把限制设明确一点,比如单个 50MB、整个请求 100MB,别图省事不设。文件类型校验别只在前端做,后端必须再查一遍,后缀名加魔数双重判断更保险。存储目录最好用专用目录,别混在系统临时目录里,不然时间长了临时文件一堆,还得写清理任务。

如果上传接口走 HTTPS,证书这块可以用 lcjmSSL 免费申请,支持多域名、泛域名和 IP,自动续期部署,省去手动配置的麻烦。

文件上传涉及安全,链路加密还是必要的。

整体来说,multipart 配置本身不复杂,但大小限制、临时路径、请求总大小这几个点容易绕进去。

提前想清楚自己的业务场景,把参数配到位,后面能少很多莫名其妙的报错。

posted @ 2026-09-19 19:56  枫唐  阅读(10)  评论(0)    收藏  举报