NestJS 服务器上传部署在 vercel 上的文件在日志 vercel 中出现错误

问题描述 投票:0回答:1

希望您今天过得愉快!我正在开发一个 NestJS 服务器,并实现了一个在我的本地服务器上完美运行的文件上传功能。我可以看到上传的图像及其 URL。但是,将我的 NestJS 服务器部署到 Vercel 后,我遇到了 500 状态错误,并且日志显示以下错误:

Error: EROFS: read-only file system, mkdir '/var/task/src/uploads'

错误日志:

*(node:9) ExperimentalWarning: vm.USE_MAIN_CONTEXT_DEFAULT_LOADER is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
Error: EROFS: read-only file system, mkdir '/var/task/src/uploads'
    at Object.mkdirSync (node:fs:1372:26)
    at sync (/var/task/node_modules/mkdirp/index.js:74:13)
    at Function.sync (/var/task/node_modules/mkdirp/index.js:80:24)
    at new DiskStorage (/var/task/node_modules/multer/storage/disk.js:21:12)
    at module.exports 
  errno: -30,
  code: 'EROFS',
  syscall: 'mkdir',
  path: '/var/task/src/uploads'
}
Node.js process exited with exit status: 1. The logs above can help with debugging the issue.
}*

我的代码:

  @UseInterceptors(
    FileFieldsInterceptor([{ name: 'image', maxCount: 5 }], {
      limits: { fileSize: 2000000 },

      storage: diskStorage({
        // destination: resolve(__dirname, '..', 'uploads', 'blogCover'),

        // destination: '/tmp/blogCover', // Use /tmp directory

        destination: (req, file, cb) => {
          const dir = '/tmp/blogCover'; // Use /tmp directory
          fs.mkdirSync(dir, { recursive: true }); // Create the directory if it doesn't exist
          cb(null, dir);
        },

        filename: (req, file, cb) => {
          const filename = path
            .parse(file.originalname)
            .name.replace(/\s+/g, '_'); // Remove spaces
          const extension = path.parse(file.originalname).ext;
          return cb(null, `${filename}${extension}`);
        },
      }),

      fileFilter: (req, file, cb) => {
        const extension = path.parse(file.originalname).ext;

        if (extension !== '.png') {
          return cb(new BadRequestException('must be pngs'), false);
        }
        return cb(null, true);
      },
    }),
  )

方法上传文件:

  UploadFile(
    @Res() res,
    @Req() req,
    @Body() body: any,
    // @UploadedFile() image: Express.Multer.File,
    @UploadedFiles() files: { image?: Express.Multer.File[] },
  ) {
    try {
      let fileUrl;
      const pictures = [];
      // console.log('uploadcontroler:', body, files);
      // console.log ('USER : ', req.user);
      if (!files.image) {
        throw new BadRequestException('select (img first .png)');
      }
      const getImagsInFiles = files.image.map((img) => {
        // console.log(img, 'img in the map');
        // console.log(img.filename, 'filename img in the map');
        fileUrl = `${req.protocol}://${req.get('host')}/uploads/blogCover/${img.filename}`;
        return pictures.push({ img: fileUrl, Picid: new Date() });
      });

      // Save images or data to JSON in /tmp
      const filePath = path.join('/tmp', 'data.json');
      fs.writeFileSync(filePath, JSON.stringify(pictures));

      console.log('FILEURL', fileUrl);
      // * saved upload pictures from user
      this.uploadServices.saveUserPictures({
        userId: req.user.id,
        url: pictures,
      });

      return res.send({
        data: { picsUploads: pictures, countPics: getImagsInFiles },
        message: 'image is uploaded',
        status: 201,
      });
    } catch (err) {
      console.log('upload file error', err);
      return res.send({
        data: { err: err },
        message: 'select image first extension:image.png',
        status: 404,
      });
    }
  }

我尝试过的: 我尝试使用/tmp目录进行临时文件存储,但部署时仍然出现错误。

这个错误是什么:EROFS:只读文件系统,打开?我该如何解决它#314

但是这个链接对我没有帮助。

这是我的代码nestjs,我尝试上传文件:

感谢大家帮助我解决这个问题。

file-upload deployment upload nestjs vercel
1个回答
0
投票

您遇到的错误

EROFS: read-only file system
是因为 Vercel 上的文件系统是只读的(
/tmp
目录除外)。当尝试将需要文件上传的应用程序部署到 Vercel 等文件系统不可变的无服务器平台时,这是一个常见问题。

解决此问题的方法如下:

1. 使用
/tmp
临时存储目录

您已经在尝试使用

/tmp
目录,这是正确的,因为它是 Vercel 上唯一可写的目录。但是,请确保所有文件操作(包括文件创建、读取和写入)都仅限于该目录。

2. 使用云存储服务

如果您需要保留文件,请考虑使用云存储服务,例如 Amazon S3、Google Cloud Storage 或其他服务。这样,您就可以将文件直接上传到云端,无需写入本地文件系统。

3. 检查并重构您的代码

重构代码以正确处理上传,确保所有文件操作都使用

/tmp
目录。另外,避免尝试在此目录之外创建目录或文件。

这是代码的更新版本,以确保其在 Vercel 上正常工作:

import {
  Controller,
  Post,
  UseInterceptors,
  UploadedFiles,
  Res,
  Req,
  BadRequestException,
} from '@nestjs/common';
import { FileFieldsInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import * as fs from 'fs';
import * as path from 'path';

@Controller('upload')
export class UploadController {
  @Post('file')
  @UseInterceptors(
    FileFieldsInterceptor([{ name: 'image', maxCount: 5 }], {
      limits: { fileSize: 2000000 },

      storage: diskStorage({
        destination: (req, file, cb) => {
          const dir = '/tmp/blogCover'; // Ensure /tmp directory is used
          fs.mkdirSync(dir, { recursive: true }); // Create the directory if it doesn't exist
          cb(null, dir);
        },
        filename: (req, file, cb) => {
          const filename = path
            .parse(file.originalname)
            .name.replace(/\s+/g, '_'); // Remove spaces
          const extension = path.parse(file.originalname).ext;
          cb(null, `${filename}${extension}`);
        },
      }),

      fileFilter: (req, file, cb) => {
        const extension = path.parse(file.originalname).ext;
        if (extension !== '.png') {
          return cb(new BadRequestException('Must be a .png file'), false);
        }
        cb(null, true);
      },
    }),
  )
  async UploadFile(
    @Res() res,
    @Req() req,
    @UploadedFiles() files: { image?: Express.Multer.File[] },
  ) {
    try {
      if (!files.image) {
        throw new BadRequestException('Please select an image with a .png extension');
      }

      const pictures = files.image.map((img) => {
        const fileUrl = `${req.protocol}://${req.get('host')}/uploads/blogCover/${img.filename}`;
        return { img: fileUrl, Picid: new Date() };
      });

      // Optionally save image data to /tmp directory
      const filePath = path.join('/tmp', 'data.json');
      fs.writeFileSync(filePath, JSON.stringify(pictures));

      // Save images to your database or cloud storage
      await this.uploadServices.saveUserPictures({
        userId: req.user.id,
        url: pictures,
      });

      return res.status(201).send({
        data: { picsUploads: pictures },
        message: 'Image(s) uploaded successfully',
      });
    } catch (err) {
      console.error('Upload file error:', err);
      return res.status(400).send({
        data: { err: err.message },
        message: 'Failed to upload image(s)',
      });
    }
  }
}

4. 部署和测试

进行这些更改后,再次将应用程序部署到 Vercel 并测试文件上传功能以确保其按预期工作。

5. 考虑使用 Vercel 的文件存储解决方案

或者,您可以探索 Vercel 的集成文件存储选项或针对无服务器环境优化的第三方服务。

通过执行这些步骤,您应该能够解决

EROFS
错误并在 Vercel 上成功部署具有文件上传功能的 NestJS 应用程序。

© www.soinside.com 2019 - 2024. All rights reserved.