使用带有请求头{"Content-Type": "multipart/form-data;"}的请求发送空的req.body。

4
我正在尝试将下面的formData保存到MongoDB中。在下面的付款信息中,“attachments”是一个 FileList。
在头部内容类型为multipart/form-data时,创建控制器响应返回空的body。否则,创建控制器添加所有字段但不添加附件,导致返回一个空数组。
我在控制器上该怎么做才能创建带有附件的付款呢?

const handlePaymentSubmit = async (e) => {
    e.preventDefault();
    let payment = new FormData();
    payment.append("payee", user.id);
    payment.append("amount", paymentAmount);
    payment.append("code", paymentCode);
    payment.append("method", paymentMethod);
    payment.append("applicationId", applicationId);
    payment.append("attachments", attachments);
    await createPayment(payment);
    {
      isSuccess && dispatch(reset());
    }
  };

在 createPayment RTK 端点中,我将头文件 content-type 设置为多部分表单数据。

createPayment: builder.mutation({
      query: (payment) => ({
        url: "/api/payments/",
        method: "POST",
        body: payment,
        headers: {
          "Content-Type": "multipart/form-data;",
        },
      }),

在后端,我使用Multer中间件设置如何存储文件。

import multer from "multer";

var storeImage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "uploads/payments");
  },
  filename: function (req, file, cb) {
    let ext = file.originalname.substring(file.originalname.lastIndexOf("."));
    let name = file.originalname.substring(0, file.originalname.indexOf("."));
    cb(null, name + "-" + Date.now() + ext);
  },
});

export const storage = multer({
  storage: storeImage,
  fileFilter: function (req, file, cb) {
    if (
      (file.mimetype =
        "image/png" || "image/jpg" || "image/jpeg" || "application/pdf")
    ) {
      cb(null, true);
    } else {
      console.log("Only pdf, jpg and Png Supported");
      cb(null, false);
    }
  },
  limits: {
    fileSize: 1024 * 1024 * 2,
  },
});

在我的创建控制器中创建支付。

import asyncHandler from "express-async-handler";
import formidable from "formidable";
import Payment from "../../models/payment.js";

export const createPayment = asyncHandler(async (req, res) => {
  const { payee, amount, code, method, applicationId } = await req.body;

  if (!payee || !amount || !code || !method || !applicationId) {
    res.status(400);
    throw new Error("Please add all required fields");
  }

  if (req.files) {
    let path = "";
    req.files.forEach(function (files, index, arr) {
      path = path + files.path + ",";
    });
    path = path.substring(0, path.lastIndexOf(","));
  }

  const attachments = req.files.map((attachment) => ({
    path: attachment.path,
    name: attachment.filename,
    size: `${(attachment.size / 1000).toFixed(2).toString()} KBs`,
  }));

  const payment = await Payment.create({
    payee,
    amount,
    code,
    method,
    applicationId,
    attachments,
  });

  res.status(200).json(payment);
});


请从您的headers中移除分号: { "Content-Type": "multipart/form-data", }, - Brijesh Dave
@BrijeshDave,感谢您发现这个问题。但是,我仍然得到一个空的请求体。 - Breldan
您定义的 storage,您确定在中间件中使用它了吗? - Youssouf Oumar
请发布您的路由文件和配置Express应用程序的app.js文件。 - Brijesh Dave
1个回答

3

"Content-Type": "multipart/form-data;"这在rtk中不起作用。默认情况下,当你使用RTK Mutation发送数据时,它会自动将数据序列化为字符串格式,然后再通过网络发送。然而,如果你想发送表单数据而不对其进行字符串化处理,你可以使用formData选项。

以下是一个示例,演示如何在RTK Mutation查询中使用formData选项:

createPayment: builder.mutation({
      query: (payment) => ({
        url: "/api/payments/",
        method: "POST",
        body: payment,
        formData: true
      }),

在这个例子中,createPayment 变异将表单数据发送到服务器而不串行化它。formData 选项设置为 true,告诉 RTK Mutation 不要序列化数据。
请注意,当使用 formData 选项时,Content-Type 标头将自动设置为 multipart/form-data,这是发送表单数据的标准格式。

1
你的答案非常正确。它帮助我解决了一个类似的问题。谢谢。 - Bravo Stack
无法在服务器上获取文件,很奇怪 - undefined
我可以在服务器上获取文件,但没有内容。Symfony\Component\HttpFoundation\FileBag {#49 // app/Http/Controllers/PostsController.php:29 #parameters: [] } - undefined
这应该可以运行。尝试打印完整的请求并进行调试。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接