能否用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
相关产品推荐
相关产品推荐

