NestJS部署Vercel后文件上传遇EROFS只读文件系统错误求助
NestJS + Vercel 文件上传 EROFS 错误修复
问题分析
错误日志显示代码尝试创建/var/task/src/uploads目录,但Vercel Serverless运行环境中仅/tmp目录具备可写权限。即便你已配置使用/tmp/blogCover,仍出现该错误,说明代码中仍存在写入只读目录的逻辑残留。
分步解决方案
1. 定位并清理所有只读目录写入逻辑
- 检查
uploadServices.saveUserPictures方法:确认该方法是否硬编码了/var/task/src/uploads这类只读路径,若有则修改为/tmp下的路径,或直接改为云存储逻辑。 - 排查代码残留:确保没有其他multer配置、文件操作片段仍指向旧的只读目录(比如已注释的
destination: resolve(__dirname, '..', 'uploads', 'blogCover')是否在其他分支被启用)。
2. 优化multer存储配置
调整destination逻辑,使用path.join避免路径拼接错误,同时确保目录创建逻辑稳定:
storage: diskStorage({ destination: (req, file, cb) => { // 使用path.join确保路径格式正确 const dir = path.join('/tmp', 'blogCover'); fs.mkdirSync(dir, { recursive: true }); cb(null, dir); }, filename: (req, file, cb) => { const filename = path .parse(file.originalname) .name.replace(/\s+/g, '_'); const extension = path.parse(file.originalname).ext; cb(null, `${filename}${extension}`); }, }),
3. 解决静态文件访问问题
你生成的fileUrl指向/uploads/blogCover/,但Vercel不会自动暴露/tmp目录下的文件,该URL无法被外部访问。正确做法是将文件转存到云存储服务:
// 以Cloudinary为例,先安装依赖:npm install cloudinary import { v2 as cloudinary } from 'cloudinary'; // 在模块初始化时配置云存储 cloudinary.config({ cloud_name: '你的云存储名称', api_key: '你的API密钥', api_secret: '你的API密钥', }); // 修改UploadFile方法中的文件处理逻辑 const getImagsInFiles = await Promise.all(files.image.map(async (img) => { // 上传文件到云存储 const uploadResult = await cloudinary.uploader.upload(img.path, { folder: 'blogCover', format: 'png', }); // 使用云存储的公开URL const fileUrl = uploadResult.secure_url; pictures.push({ img: fileUrl, Picid: new Date() }); // 清理临时文件(可选) await fs.promises.unlink(img.path); }));
4. 注意临时目录的局限性
Vercel的/tmp目录是临时存储,函数执行结束后会被清理,且容量有限(通常为512MB),绝对不能用于长期存储用户上传的文件,必须依赖云存储服务实现持久化。
内容的提问来源于stack exchange,提问作者mohsen ab
相关产品推荐
相关产品推荐

