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

解决Axios上传jpg图片时后端识别为jpeg导致Sharp报错问题

问题:JPG图片上传后Sharp处理找不到文件的问题

我从React前端向Node.js后端发送.jpg图片,后端识别文件类型为jpeg,但multer仍按原后缀将其保存为.jpg,导致后续Sharp处理图片时因找不到文件报错。我尝试在multer保存文件和Sharp定义输入路径的两处统一文件类型,但未解决问题。

前端代码

function App() {
  const [image, setImage] = useState("");
  function handleImage(e) {
    console.log(e.target.files);
    setImage(e.target.files[0]);
  }
  function handleApi() {
    const formData = new FormData();
    formData.append("image", image);
    formData.append("pfp", "yes");
    formData.append("filetype", image.type )
    console.log('hello')
    console.log(image)
    console.log(formData)
    axios
      .post("http://localhost:3001/users/editprofile/1", formData, {
        headers: {
          "Content-Type": "multipart/form-data",
        },
      })
      .then((res) => {
        console.log(res);
      });
  }
  return (
    <div>
      <input type="file" name="file" onChange={handleImage} />
      <button onClick={handleApi}>submit</button>
    </div>
  );
}

后端代码

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "images/temp");
  },
  filename: function (req, file, cb) {
    const id = req.params.id;
    let extention = path.extname(file.originalname);
    cb(null, `pfp_${id}` + extention);
  },
});

router.post("/editprofile/:id", upload.single("image"), async (req, res) => {
  const id = req.params.id;
  const { pfp, bio, filetype } = req.body;
  console.log(bio);
  console.log(req.body);
  if (pfp) {
    const typetemp = filetype.split("/");
    const type = typetemp[typetemp.length - 1];

    var imput = path.join(
      __dirname,
      "..",
      "images/temp",
      "pfp_" + id + "." + type
    );
    var output = path.join(__dirname, "..", "images/temp", id + "png.png");
    var newimage = path.join(
      __dirname,
      "..",
      "images/profile_pictures",
      "pfp_" + id + ".png"
    );

    try {
      const metadata = await sharp(imput).metadata();
      if (metadata.format != "png") {
        await sharp(imput).toFormat("png", { palette: true }).toFile(output);
      } else {
        await sharp(imput).toFile(output);
      }
      if (metadata.height > metadata.width) {
        var topcut = Math.round((metadata.height - metadata.width) / 2);
        await sharp(imput)
          .extract({
            width: metadata.width,
            height: metadata.width,
            left: 0,
            top: topcut,
          })
          .toFile(newimage);
      } else if (metadata.height < metadata.width) {
        var leftcut = Math.round((metadata.width - metadata.height) / 2);
        console.log(leftcut);
        await sharp(imput)
          .extract({
            width: metadata.height,
            height: metadata.height,
            left: leftcut,
            top: 0,
          })
          .toFile(newimage);
      }
      const metadatanew = await sharp(newimage).metadata();
      console.log(metadatanew);
      var newpfp = id + ".png";
    } catch (error) {
      console.log(error);
    }
  }
});

报错信息

[Object: null prototype] { pfp: 'yes', filetype: 'image/jpeg' }
[Error: Input file is missing: D:\programmeerstuff\javascript\pws\version 0.0.1\server\images\temp\pfp_1.jpeg]

解决方法

问题核心是multer保存的文件名后缀和Sharp读取的后缀不一致:multer用了原文件的.jpg后缀,而Sharp根据前端传来的filetype拼接成了.jpeg,导致路径错误。

直接使用multer上传后提供的真实文件路径是最可靠的方案,完全避免后缀匹配问题:

  1. 后端中,multer上传完成后会把文件的完整信息存入req.file对象,直接取req.file.path作为Sharp的输入路径即可。
  2. 无需前端传递filetype字段,也不用手动拼接文件名,彻底消除路径不匹配的可能。

修改后的后端关键代码:

router.post("/editprofile/:id", upload.single("image"), async (req, res) => {
  const id = req.params.id;
  const { pfp, bio } = req.body;
  if (pfp) {
    // 直接使用multer保存的真实文件路径
    const inputPath = req.file.path;
    var output = path.join(__dirname, "..", "images/temp", `${id}_temp.png`);
    var newimage = path.join(
      __dirname,
      "..",
      "images/profile_pictures",
      `pfp_${id}.png`
    );

    try {
      const metadata = await sharp(inputPath).metadata();
      // 后续逻辑保持不变,仅替换输入路径为inputPath
      if (metadata.format !== "png") {
        await sharp(inputPath).toFormat("png", { palette: true }).toFile(output);
      } else {
        await sharp(inputPath).toFile(output);
      }
      if (metadata.height > metadata.width) {
        var topcut = Math.round((metadata.height - metadata.width) / 2);
        await sharp(inputPath)
          .extract({
            width: metadata.width,
            height: metadata.width,
            left: 0,
            top: topcut,
          })
          .toFile(newimage);
      } else if (metadata.height < metadata.width) {
        var leftcut = Math.round((metadata.width - metadata.height) / 2);
        await sharp(inputPath)
          .extract({
            width: metadata.height,
            height: metadata.height,
            left: leftcut,
            top: 0,
          })
          .toFile(newimage);
      }
      const metadatanew = await sharp(newimage).metadata();
      console.log(metadatanew);
      var newpfp = `${id}.png`;
    } catch (error) {
      console.log(error);
    }
  }
});

同时前端可以删除formData.append("filetype", image.type)这一行代码,该字段已不再需要。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:37:09