Nest.js+Cloudinary单图上传问题:无法覆盖用户头像
问题
我尝试将用户头像上传至Cloudinary,最初用uploadStreamFile方法能正常运行,但为了实现用户更换头像时覆盖旧头像的需求,根据Cloudinary文档改成了upload方法,结果出问题了。
原可用方法
uploadStreamFile(file: Express.Multer.File): Promise<CloudinaryResponse> { return new Promise<CloudinaryResponse>((resolve, reject) => { const uploadStream = cloudinary.uploader.upload_stream( (error, result) => { if (error) return reject(error); resolve(result); }, ); streamifier.createReadStream(file.buffer).pipe(uploadStream); }); }
修改后的方法
async uploadFile(file: Express.Multer.File, userId: string) { console.log(`FILE: ${file}`) console.log(`FILE NAME ${file.filename}`) console.log(`ORG NAME ${file.originalname}`) console.log(`FIELD NAME ${file.fieldname}`) const uploadResponse = await cloudinary.uploader.upload(file.originalname, { folder: 'avatars', public_id: userId, overwrite: true, });
执行报错信息
649439028425fb78cabf8601 FILE: [object Object] FILE NAME undefined ORG NAME 103_gargamel.jpg FIELD NAME file [Nest] 62390 - 07/01/2023, 9:33:00 PM ERROR [ExceptionsHandler] Object: { "error": { "errno": -2, "code": "ENOENT", "syscall": "open", "path": "103_gargamel.jpg" } }
控制器代码
@Post('upload/:userId') @UseInterceptors(FileInterceptor('file')) uploadImage(@UploadedFile() file: Express.Multer.File, @Param('userId') userId: string) { return this.cloudinaryService.uploadFile(file, userId); }
前端已经正确传递文件和userId,我试过传入其他字符串或二进制缓冲区,但TypeScript要求参数必须是字符串,请问问题出在哪?
解答
问题核心是cloudinary.uploader.upload()的第一个参数用法错误:
- 你传入的
file.originalname是文件名字符串,Cloudinary会将其当作本地文件路径去读取,但当前运行目录下不存在该文件,因此触发ENOENT(找不到文件)错误。 - 原方法用
upload_stream直接处理内存中的文件缓冲区,而upload方法要处理内存中的文件,需传入数据URI(符合TypeScript的字符串要求)。
修改后的正确方法:
async uploadFile(file: Express.Multer.File, userId: string) { // 将内存中的文件缓冲区转为Data URI格式 const fileDataUri = `data:${file.mimetype};base64,${file.buffer.toString('base64')}`; const uploadResponse = await cloudinary.uploader.upload(fileDataUri, { folder: 'avatars', public_id: userId, overwrite: true, }); return uploadResponse; }
补充说明:从日志中file.filename为undefined可以判断,你使用的是Multer的memoryStorage(内存存储模式),文件仅存在于内存缓冲区中,无法通过本地路径读取。如果后续改为磁盘存储模式,可直接传入file.path给upload方法。
内容的提问来源于stack exchange,提问作者mcdominik
相关产品推荐
相关产品推荐

