You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否用Next.js Server Actions实现文件上传至项目目录?

用Next.js Server Actions实现求职者信息与文件上传

完全可以通过Next.js Server Actions实现你的需求:上传简历(PDF/文档/表格/图片等)到项目目录,同时存储求职者的姓名、邮箱、电话信息。你不用纠结multipart/form-data的问题——Server Actions会自动处理前端表单提交的所有数据,包括File对象,不需要手动设置请求头。

你的现有代码问题分析

你当前的代码里没必要引入form-data包,因为前端通过Server Actions传递的File对象已经是标准的Web File接口,可以直接读取其二进制内容。另外还有几个需要调整的点:

  • __dirname在Server Actions的运行环境中路径指向可能不符合预期,建议用process.cwd()定位项目根目录
  • 同步写入文件fs.writeFileSync会阻塞线程,推荐用异步方法
  • 硬编码.pdf后缀不够灵活,应该根据上传文件的类型动态设置

修正后的完整代码示例

"use server";
import prisma from "@/utils/prisma";
import fs from "fs/promises";
import path from "path";
import { v4 as uuid } from "uuid";

// 可选:限制允许上传的文件类型
const ALLOWED_MIME_TYPES = [
  "application/pdf",
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  "application/vnd.ms-excel",
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  "image/jpeg",
  "image/png"
];

export async function uploadApplicant(
  name: string,
  email: string,
  tel: string,
  file: File | null
) {
  try {
    if (!file) throw new Error("请上传简历文件");
    
    // 验证文件类型
    if (!ALLOWED_MIME_TYPES.includes(file.type)) {
      throw new Error("仅支持PDF、Word、Excel或图片格式的文件");
    }

    // 生成唯一文件名,保留原文件后缀
    const fileExt = path.extname(file.name);
    const fileName = `${uuid()}${fileExt}`;
    
    // 将File对象转为Buffer
    const arrayBuffer = await file.arrayBuffer();
    const fileBuffer = Buffer.from(arrayBuffer);

    // 构建文件存储路径(基于项目根目录)
    const uploadDir = path.join(process.cwd(), "public", "uploads");
    // 自动创建uploads目录(如果不存在)
    await fs.mkdir(uploadDir, { recursive: true });
    const filePath = path.join(uploadDir, fileName);

    // 异步写入文件
    await fs.writeFile(filePath, fileBuffer);

    // 存入数据库
    await prisma.applicant.create({
      data: {
        name,
        tel,
        email,
        fileName,
        originalFileName: file.name // 可选:存储原文件名,方便后续识别
      },
    });

    return { success: true, message: "简历上传成功" };
  } catch (error) {
    console.error("上传失败:", error);
    return { success: false, message: error instanceof Error ? error.message : "未知错误" };
  }
}

关键注意事项

  • 目录权限:通过fs.mkdir({ recursive: true })确保public/uploads目录存在,避免写入失败
  • 文件大小限制:Next.js默认限制Server Actions请求大小为1MB,若需要上传大文件,需在next.config.js中配置:
    /** @type {import('next').NextConfig} */
    const nextConfig = {
      serverActions: {
        bodySizeLimit: "10mb" // 根据需求调整允许的最大文件大小
      }
    };
    module.exports = nextConfig;
    
  • 生产环境建议:虽然可以将文件存在public目录,但Vercel等平台的静态资源目录不适合频繁写入,生产环境更推荐使用云存储服务,只需调整文件写入逻辑为上传到云存储,数据库存储文件URL即可
  • 安全防护:除了验证文件MIME类型,还可以对文件名进行转义处理,避免路径遍历攻击;同时可添加文件大小限制,防止超大文件占用服务器资源

内容的提问来源于stack exchange,提问作者Ismoiljon Abduqahhorov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 00:13:10