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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:33:21