希望您今天过得愉快!我正在开发一个 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,我尝试上传文件:
感谢大家帮助我解决这个问题。
您遇到的错误
EROFS: read-only file system
是因为 Vercel 上的文件系统是只读的(/tmp
目录除外)。当尝试将需要文件上传的应用程序部署到 Vercel 等文件系统不可变的无服务器平台时,这是一个常见问题。
解决此问题的方法如下:
/tmp
临时存储目录您已经在尝试使用
/tmp
目录,这是正确的,因为它是 Vercel 上唯一可写的目录。但是,请确保所有文件操作(包括文件创建、读取和写入)都仅限于该目录。
如果您需要保留文件,请考虑使用云存储服务,例如 Amazon S3、Google Cloud Storage 或其他服务。这样,您就可以将文件直接上传到云端,无需写入本地文件系统。
重构代码以正确处理上传,确保所有文件操作都使用
/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)',
});
}
}
}
进行这些更改后,再次将应用程序部署到 Vercel 并测试文件上传功能以确保其按预期工作。
或者,您可以探索 Vercel 的集成文件存储选项或针对无服务器环境优化的第三方服务。
通过执行这些步骤,您应该能够解决
EROFS
错误并在 Vercel 上成功部署具有文件上传功能的 NestJS 应用程序。