一、文件上传 基础概念

文件上传是 Web 应用的核心功能,允许客户端将图片、文档、压缩包等文件发送到服务器保存。核心风险:若未做安全校验,极易被上传木马、后门、恶意脚本,导致服务器被入侵。


二、基本原理

1. 客户端流程

  1. 使用 <form> 表单提交
  2. 必须设置:enctype="multipart/form-data"
  3. 使用 <input type="file"> 选择文件
  4. 浏览器将文件拆分为 ** multipart 数据流 ** 发送

2. 服务端流程

  1. 接收 multipart 数据流
  2. 解析:文件名、MIME 类型、文件内容、表单字段
  3. 校验文件合法性(类型、大小、后缀、内容)
  4. 生成安全文件名,写入磁盘 / 云存储
  5. 返回访问路径或结果

三、核心技术与依赖

1. Servlet 3.0+ 原生上传

  • 无需第三方包
  • 注解:@MultipartConfig
  • 方法:request.getPart() / getParts()

2. Apache Commons FileUpload

  • 兼容低版本 Servlet
  • 依赖:commons-fileupload + commons-io

3. Spring 系列(Spring Boot / Spring MVC)

  • 接口:MultipartFile
  • 自动封装解析逻辑
  • 企业开发首选

四、具体实现(代码完善版)

1. Servlet 3.0+ 原生实现

前端表单

<form action="/upload" method="post" enctype="multipart/form-data">
    用户名:<input type="text" name="username"><br>
    上传文件:<input type="file" name="file"><br>
    <button type="submit">提交</button>
</form>

服务端 Servlet

@WebServlet("/upload")
@MultipartConfig(
    fileSizeThreshold = 1024 * 1024,     // 1MB 内存阈值
    maxFileSize = 1024 * 1024 * 10,      // 单文件最大 10MB
    maxRequestSize = 1024 * 1024 * 50    // 总请求最大 50MB
)
public class FileUploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=utf-8");

        String username = request.getParameter("username");
        Part part = request.getPart("file");
        String fileName = part.getSubmittedFileName();

        // 安全处理:UUID 重命名,防止覆盖与路径穿越
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        String uuidName = UUID.randomUUID() + suffix;

        String savePath = getServletContext().getRealPath("/uploads");
        File dir = new File(savePath);
        if (!dir.exists()) dir.mkdirs();

        part.write(savePath + File.separator + uuidName);
        response.getWriter().write("上传成功:" + uuidName);
    }
}

2. Spring Boot 实现(企业标准写法)

Controller(最安全、最规范)

@RestController
@RequestMapping("/api")
public class UploadController {
    // 上传目录(建议写到 application.yml)
    private static final String UPLOAD_PATH = "D:/uploads/";

    @PostMapping("/upload")
    public Result upload(
            @RequestParam String username,
            @RequestParam MultipartFile file) {

        if (file.isEmpty()) {
            return Result.fail("请选择文件");
        }

        // 1. 校验文件类型(白名单)
        String contentType = file.getContentType();
        List<String> allowTypes = Arrays.asList(
            "image/jpeg", "image/png", "image/gif"
        );
        if (!allowTypes.contains(contentType)) {
            return Result.fail("不允许的文件类型");
        }

        // 2. 安全文件名(UUID)
        String original = file.getOriginalFilename();
        String suffix = original.substring(original.lastIndexOf("."));
        String newName = UUID.randomUUID() + suffix;

        try {
            Files.write(Paths.get(UPLOAD_PATH + newName), file.getBytes());
            return Result.success("上传成功:" + newName);
        } catch (IOException e) {
            return Result.fail("上传失败:" + e.getMessage());
        }
    }
}

application.yml 配置(推荐)

spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 50MB

五、关键配置与优化

  1. 文件大小限制
    • maxFileSize:单文件上限
    • maxRequestSize:整个请求上限
  2. 临时文件目录
    • 防止系统自动清理导致上传失败
  3. 文件名安全处理
    • 使用 UUID 重命名
    • 过滤 / \ .. : * ? 等特殊字符
  4. 存储方案
    • 单机:本地目录
    • 分布式:阿里云 OSS / 腾讯云 COS / MinIO

六、安全风险与防御

1. 常见漏洞

  • 文件上传漏洞:上传 .jsp .php .asp 木马
  • 路径穿越:文件名使用 ../ 穿透目录
  • 文件名覆盖:同名文件覆盖服务器文件
  • 超大文件攻击:占用磁盘与带宽

2. 防御措施(必须全部做)

  1. 后缀白名单:只允许 .jpg/.png/.gif/.pdf
  2. MIME 类型校验
  3. 文件内容校验:检查文件头(幻数)
  4. 重命名文件:UUID 生成新名称
  5. 上传目录不可执行:禁止解析脚本
  6. 限制文件大小
  7. 病毒扫描(企业级)
  8. 存储到非 Web 目录

七、高级功能

  • 分片上传:大文件分块上传、断点续传
  • 异步上传:Ajax / Axios 无刷新上传
  • 跨域支持@CrossOrigin / 网关配置
  • 预览 / 下载:提供静态资源映射
  • 水印 / 压缩:图片处理

八、思维导图


九、考试 / 面试必背高频要点

  1. 文件上传表单必须加:enctype="multipart/form-data"
  2. Spring 上传使用接口:MultipartFile
  3. 最容易出现的漏洞:文件上传漏洞
  4. 防御三件套:后缀白名单 + 类型校验 + UUID 重命名
  5. 上传目录必须:不可执行脚本
  6. 大文件方案:分片上传

 

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐