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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 16:12:47