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

Multer上传图片时Axios请求req.file为undefined的问题解决

Multer图片上传:Postman正常但Axios请求时req.file为undefined(400错误)

问题现象

  • Multer实现的图片上传功能,通过Postman测试完全正常
  • 前端使用Axios发送请求时,后端req.file始终为undefined,但req.body能正确获取到预期数据
  • 前端收到400错误响应,后端日志输出"Please upload an image"

相关代码

Multer配置(multer.ts)

import { Request, Response, NextFunction } from "express";
import multer from "multer";

const storage = multer.diskStorage({
  destination: "uploads/",
  filename: (req, file, cb) => {
    const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
    cb(null, uniqueSuffix);
  },
});

const uploads = multer({
  storage: storage,
  limits: {
    fileSize: 1024 * 1024 * 5,
    files: 1,
    fieldSize: 1024 * 1024 * 5,
  },
  fileFilter: (req, file, cb) => {
    if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
      cb(null, true);
    } else {
      cb(new Error("File type not supported!"));
    }
  },
});

interface RequestWithUser extends Request {
  user?: {
    id: number;
    email: string;
  };
}

export function uploadImage(
  req: RequestWithUser,
  res: Response,
  next: NextFunction
) {
  uploads.single("image")(req, res, (err) => {
    if (err instanceof multer.MulterError) {
      console.error("MulterError =>", err.message);
      return res.status(400).json({ message: err.message });
    }
    if (err) {
      console.error("MulterError =>", err.message);
      return res.status(400).json({ message: err.message });
    }
    if (!req.file) {
      console.error("Please upload an image");
      return res.status(400).json({ message: "Please upload an image" });
    }

    console.log("req.body MWW =>", req.body);
    console.log("req.file MWW =>", req.file);
    next();
  });
}

路由配置

router.post(
  "/create-image",
  authorize,
  uploadImage,
  createImageController.createImage
);

原Axios请求代码

const handleGenerateImage = async (prompt: string, image: string) => {
    const formData = new FormData();

     for (const [key, value] of Object.entries({ prompt, image })) {
       formData.append(key, value as string | Blob);
     }

     console.log("formData", formData);

    try {
      const result = await axios.post(
        "http://localhost:5000/api/create-image",
        formData,
        {
          responseType: "json",
          headers: {
            Accept: "multipart/form-data",
            "Content-Type": "multipart/form-data",
            Authorization: `Bearer ${TOKEN}`,
          },
        }
      );
      console.log("result", result);
      return result;
    } catch (error) {
      console.log("error", error);
      return;
    }
  };

错误信息与日志

  • 前端错误日志:error [AxiosError: Request failed with status code 400]
  • FormData日志:formData {"_parts": [["prompt", "Superman"], ["image", "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FstickerAI-4f69cda2-177b-4e6a-9b97-2784a47b4c88/ImagePicker/2fcasdf1-30f5-4149-89a1-0304b7b3acfc.jpeg"]]}
  • 后端返回响应:
{
   "_bodyBlob":{
      "_data":{
         "__collector":[
            "Object"
         ],
         "blobId":"e40a7871-51f9-4678-a309-e467bcdbab3e",
         "offset":0,
         "size":36
      }
   },
   "_bodyInit":{
      "_data":{
         "__collector":[
            "Object"
         ],
         "blobId":"e40a7871-51f9-4678-a309-e467bcdbab3e",
         "offset":0,
         "size":36
      }
   },
   "bodyUsed":false,
   "headers":{
      "map":{
         "access-control-allow-origin":"*",
         "connection":"keep-alive",
         "content-length":"36",
         "content-type":"application/json; charset=utf-8",
         "date":"Mon, 29 Apr 2024 08:56:49 GMT",
         "etag":"W/\"24-RuEUrN0QtPlwvGJylleayGNbKK0\"",
         "keep-alive":"timeout=5",
         "x-powered-by":"Express"
      }
   },
   "ok":false,
   "status":400,
   "statusText":"",
   "type":"default",
   "url":"http://localhost:5000/api/create-image"
}

已尝试的无效方案

  • 从req.body提取数据手动赋值给req.file
  • 改用req.files数组接收文件
  • 移除请求头中的Content-Type字段
  • 调整Express的bodyParser配置

解决方案

问题根源在于前端仅传入了图片的URI字符串,Multer无法将普通字符串识别为文件。改为传入包含name、type、uri的完整文件对象,并将URI转为Blob后再加入FormData即可解决。

调整后的Axios请求示例

const handleGenerateImage = async (prompt: string, image: {name: string, type: string, uri: string}) => {
  const formData = new FormData();
  // 将图片URI转为Blob(以Expo环境为例)
  const fileResponse = await fetch(image.uri);
  const imageBlob = await fileResponse.blob();
  // 正确添加文件到FormData,指定文件名
  formData.append('image', imageBlob, image.name);
  formData.append('prompt', prompt);

  try {
    const result = await axios.post(
      "http://localhost:5000/api/create-image",
      formData,
      {
        responseType: "json",
        headers: {
          Authorization: `Bearer ${TOKEN}`,
          // 无需手动设置Content-Type,浏览器会自动生成带boundary的正确头
        },
      }
    );
    console.log("result", result);
    return result;
  } catch (error) {
    console.log("error", error);
    return;
  }
};

关键说明

  • 原请求中image字段是字符串类型的URI,FormData仅将其作为普通文本字段提交,Multer无法解析为文件,因此req.file为undefined,触发后端的400校验
  • 转为Blob后,FormData会按照文件格式封装数据,Multer能正常识别并解析出req.file

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 21:30:31