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

React全栈应用新增MongoDB对象时旧对象rndImageName异常变更问题

问题根源

你代码里的核心问题是**rndImageName是模块级变量**——它只会在multer.js模块第一次加载时生成一次,后续所有上传请求都会复用这个固定值。如果有多个请求并发,还会出现后生成的随机名覆盖旧值的情况,导致你看到的"重复使用同一随机名称、修改已添加食谱imageName"的问题。

优化实现方案

1. 调整图片上传接口,实时生成随机名并返回给前端

修改multer.js,移除模块级的rndImageName,每次上传时生成新的随机名,上传完成后把这个名称返回给前端:

// multer.js
const randomImageName = (bytes = 32) => crypto.randomBytes(bytes).toString('hex')

// 移除模块级变量:let rndImageName = randomImageName();

awsRouter.post('/recipeImages', upload.single('file'), async (req, res) => {
  try {
    // 每次请求生成新的随机文件名
    const rndImageName = randomImageName();
    // 可选:保留原文件扩展名,避免S3识别文件类型出错
    const fileExt = req.file.originalname.split('.').pop();
    const finalFileName = `${rndImageName}.${fileExt}`;

    const buffer = await sharp(req.file.buffer)
      .resize({ height: 1920, width: 1080, fit: 'contain' })
      .toBuffer()

    const params = {
      Bucket: bucketName,
      Key: `recipeImages/${finalFileName}`, 
      Body: buffer,
      ContentType: req.file.mimetype
    }

    const command = new PutObjectCommand(params)
    await s3.send(command)

    // 把生成的文件名返回给前端
    res.status(200).json({ imageName: finalFileName });
  } catch (error) {
    res.status(500).json({ error: '图片上传失败' });
  }
})

2. 前端流程调整

前端需要先调用图片上传接口,拿到返回的imageName,再在提交食谱表单时,把这个imageName加入到请求体中(和recipe_name、ingredients等字段一起发送)。

3. 修改食谱创建接口,从请求体获取imageName

修改recipes.js,不再从multer.js导入rndImageName,而是直接从前端提交的请求体中读取:

// recipes.js
// 移除导入:const { rndImageName } = require('./multer')

recipesRouter.post('/', async (request, response, next) => {
  try {
    const body = request.body

    const decodedToken = jwt.verify(getTokenFrom(request), process.env.SECRET)
    if (!decodedToken.id) {
      return response.status(401).json({ error: 'token invalid' })
    }
    const user = await User.findById(decodedToken.id)

    const recipe = new Recipe({
      id: body.id,
      recipe_name: body.recipe_name,
      ingredients: body.ingredients,
      instructions: body.instructions,
      speed: body.speed,
      category: body.category,
      main_ingredient: body.main_ingredient,
      diet: body.diet,
      likes: body.likes || 0,
      comments: body.comments || [],
      created: new Date(),
      // 从请求体读取前端传来的imageName
      imageName: body.imageName,
      user: user._id
    })

    const savedRecipe = await recipe.save()
    user.recipes = user.recipes.concat(savedRecipe._id)
    await user.save()

    response.status(201).json(savedRecipe)
  } catch (error) {
    next(error)
  }
})
额外优化建议
  • 降低文件名冲突概率:可以在随机名后拼接时间戳(比如${rndImageName}-${Date.now()}.${fileExt}),进一步避免极端情况的冲突。
  • 完善错误处理:给接口添加try/catch捕获异常,返回明确的错误信息,方便前端调试。
  • 使用UUID替代随机字节:如果觉得crypto.randomBytes生成的字符串过于冗长,可以用uuid库生成UUID作为文件名,可读性更好。

内容的提问来源于stack exchange,提问作者KonalaWebsites

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 01:55:02