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

Node.js使用multer上传文件遇异常:/update路由报错,仅uploadArray可用

嘿,我来帮你搞定这个multer上传的问题!你遇到的SyntaxError: Unexpected token < in JSON at position 0错误,本质是后端返回了HTML格式的错误内容,但前端期望解析JSON,所以才会报这个错。结合你的代码,咱们一步步排查修复:

1. 先把multer的错误处理改对

你现在的upload和uploadArray中间件里,遇到错误只是打个日志就直接next(),这会让错误跑到Express默认的错误处理器,它返回的是HTML页面(开头就是<),这就是前端解析失败的根源。

修改/utils/lib/account.js里的错误处理逻辑:

exports.upload = (req, res, next) => {
  upload(req, res, function (err) {
    if (err) {
      console.log(err);
      // 直接返回JSON格式的错误,不让错误继续扩散
      return res.status(400).json({message: '文件上传失败', error: err.message});
    }
    next();
  });
};

exports.uploadArray = (req, res, next) => {
  uploadArray(req, res, function (err) {
    if(err){
      console.log(err);
      return res.status(400).json({message: '文件上传失败', error: err.message});
    }
    next();
  });
};

2. 确认前端请求的Content-Type没搞错

用fields方式上传文件时,前端必须把请求的Content-Type设为multipart/form-data,绝对不能用application/json。如果前端错发了JSON格式的请求,multer根本解析不了文件和字段,会导致后续操作出错。

3. 调整update_profile控制器的文件处理逻辑

fields和array方式下,req.files的结构完全不一样:

  • array模式:req.files是一个数组,每个元素是上传的文件
  • fields模式:req.files是个对象,键是你定义的photo和cover,每个键对应一个长度为1的数组(因为你设了maxCount:1)

你之前的new控制器是针对array写的,如果update_profile直接复用了相同的逻辑,肯定会出错。给你一个适配fields的处理示例:

// update_profile控制器里的文件处理逻辑
const uri = new DataUri();
const promises = [];
const images = {}; // 用对象分别存photo和cover的URL

// 处理photo字段(如果有上传)
if (req.files?.photo) {
  const photoFile = req.files.photo[0];
  uri.format('.png', photoFile.buffer);
  promises.push(
    new Promise((resolve, reject) => {
      cloudinary.v2.uploader.upload(uri.content, (error, result) => {
        if (error) reject(error);
        images.photo = result.url;
        resolve();
      });
    })
  );
}

// 处理cover字段(如果有上传)
if (req.files?.cover) {
  const coverFile = req.files.cover[0];
  uri.format('.png', coverFile.buffer);
  promises.push(
    new Promise((resolve, reject) => {
      cloudinary.v2.uploader.upload(uri.content, (error, result) => {
        if (error) reject(error);
        images.cover = result.url;
        resolve();
      });
    })
  );
}

// 等待所有文件上传完成后执行更新
Promise.all(promises)
  .then(() => {
    // 合并上传的图片URL和表单字段
    const updateData = { ...req.body, ...images };
    // 执行你的更新操作,比如用findByIdAndUpdate
    Account.findByIdAndUpdate(req.body.id, updateData, { new: true })
      .then(updatedAccount => {
        res.json({ message: '更新成功', type: 'success', code: 200, data: updatedAccount });
      })
      .catch(err => {
        res.status(500).json({ message: '更新失败', error: err.message });
      });
  })
  .catch(err => {
    console.log(err);
    res.status(400).json({ message: '文件上传失败', error: err.message });
  });

4. 优化路由中间件的应用范围

你现在给/update路由用了.all(helper.upload),这会把multer中间件应用到所有请求方法(GET、OPTIONS等),但实际上只有POST请求需要处理文件上传。改成这样更合理:

router.route('/update')
  .all(helper.verifyToken)
  .post(helper.upload, account.update_profile) // 只在POST请求时应用upload中间件

按这几步调整后,应该就能解决你的问题了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:42:03