Node.js使用Cloudinary上传图片失败 报错TypeError无法读取属性'path'
报错根因定位
你遇到的TypeError: 无法读取属性'path'完全是代码逻辑错位导致的,现有路由代码存在4个明确错误:
- 单文件取值错位:
upload.single()是处理单文件上传的中间件,处理完成后上传的文件对象会挂载在req.file上,并非req.files(req.files是多文件上传场景的挂载属性),代码中打印req.files必然拿到undefined。 - 未定义变量解构:代码中
const {propertyImage} = files;里的files从未做过声明,也没有从请求上下文提取,解构得到的propertyImage为undefined,读取其.path属性就会直接触发报错。 - 异步流程顺序颠倒:Cloudinary的上传方法是异步执行的,代码在上传动作还没拿到返回结果时,就提前创建了
Property实例,把未赋值的image_url作为图片字段写入;同时上传回调内部声明的image_url属于块级作用域,外部代码完全无法访问到这个变量的值。 - 入库逻辑错位:
Property实例创建时没有拿到最终的图片URL,后续就算上传流程完成,也没有把返回的URL同步更新到实例上,就算不触发报错,写入数据库的图片字段也会是空值。
修正后的实现逻辑
调整流程顺序为:前置校验上传文件 -> 读取文件路径完成Cloudinary上传拿到图片URL -> 用拿到的URL创建房产实例 -> 保存房产记录 -> 关联到当前登录用户,补上全流程的错误分支判断,修正后的代码如下:
userRouter.post( '/property', upload.single('propertyImage'), passport.authenticate('jwt', { session: false }), async (req, res) => { // 前置校验:未拿到上传文件时直接返回错误 if (!req.file) { return res.status(400).json({ message: { msgBody: "未检测到上传的房产图片", msgError: true } }) } try { // 先完成Cloudinary上传,拿到返回的图片地址 const uploadResult = await cloudinary.uploader.upload( req.file.path, { folder: "/houseImage/" } ) const imageUrl = uploadResult.url // 上传成功后再创建房产实例,写入真实的图片URL const property = new Property({ street: req.body.street, town: req.body.town, area: req.body.area, PostCode: req.body.PostCode, NoBeds: req.body.NoBeds, NoBath: req.body.NoBath, NoLivingRooms: req.body.NoLivingRooms, askingPrice: req.body.askingPrice, propertyImage: imageUrl }) // 保存房产记录到数据库 await property.save() // 将房产关联到当前登录用户 req.user.properties.push(property) await req.user.save() return res.status(200).json({ message: { msgBody: "Successfully created property", msgError: false } }) } catch (err) { return res.status(500).json({ message: { msgBody: "Error has occured", msgError: true } }) } } )
注意:如果继续使用Cloudinary的回调写法实现,需要补上上传失败的分支判断,避免无校验直接读取返回结果的属性,否则上传失败时返回结果为null,也会触发空值读取的报错。
内容的提问来源于stack exchange,提问作者SeanMarc
相关产品推荐
相关产品推荐

