我有一个表格,要在数据库中添加wine 店.我使用的是react 挂钩形式.在表单中,我还要求将图像作为输入.在提交表单时,表单中的数据被转换为表单数据,然后发送到API.

这就是正在进行转换和提交表格的地方.

以下是我的API调用:

const formMethods = useForm<HotelFormData>();
  //we are not gonna destruct the formMethods object here

  const { handleSubmit } = formMethods;

  const onSubmit = handleSubmit((data: HotelFormData) => {
    console.log(data);
    //We are going to send the data to the server, but first we need to convert the data to FormData because we have imageFiles in the data and we can not send it as a JSON object
    const formData = new FormData();
    formData.append("name", data.name);
    formData.append("city", data.city);
    formData.append("country", data.country);
    formData.append("description", data.description);
    formData.append("type", data.type);
    formData.append("pricePerNight", data.pricePerNight.toString());
    formData.append("starRating", data.starRating.toString());
    formData.append("adultCapacity", data.adultCapacity.toString());
    formData.append("childCapacity", data.childCapacity.toString());
    data.facilities.forEach((facility, index) => {
      formData.append(`facilities[${index}]`, facility);
    });
    // for (let i = 0; i < data.imageFiles.length; i++) {
    //   formData.append("imageFiles", data.imageFiles[i]);
    // }
    Array.from(data.imageFiles).forEach((imageFile) => {
      formData.append("imageFiles", imageFile);
    });
    onSave(formData);
    console.log(formData);
  });
export const addMyHotel = async (formData: FormData) => {
    console.log("formData",formData)
    const response = await fetch(`${BASE_URL}/api/my-hotels`, {
        method: "POST",
        credentials: "include", //to send the cookie
        body: formData,
        
    });
    const resBody = await response.json();

    if (!response.ok) {
        throw new Error(resBody.message);
    }
    return resBody;
};

这是我的api/my-hotels分:

import express from "express";
import { Request, Response } from "express";
import { PutObjectCommand } from "@aws-sdk/client-s3";
import mime from "mime-types";
import { client } from "../index";
import multer from "multer";
import Hotel, { HotelType } from "../models/hotel";
import verifyToken from "../middleware/auth";
import { body, validationResult } from "express-validator";

const router = express.Router();

const storage = multer.memoryStorage();
const upload = multer({
  storage: storage,
  limits: {
    fileSize: 5 * 1024 * 1024, // 5MB
  },
});

//this will be the root
router.post(
  "/",
  verifyToken, //only logged in users can create hotels
  [
    body("name").notEmpty().withMessage("Name is required"),
    body("city").notEmpty().withMessage("City is required"),
    body("country").notEmpty().withMessage("Country is required"),
    body("description").notEmpty().withMessage("Description is required"),
    body("type").notEmpty().withMessage("Type is required"),
    body("pricePerNight")
      .notEmpty()
      .isNumeric()
      .withMessage("Price per night must be a number"),
    body("adultCapacity")
      .notEmpty()
      .isNumeric()
      .withMessage("Adult capacity must be a number"),
    body("childCapacity")
      .notEmpty()
      .isNumeric()
      .withMessage("Child capacity must be a number"),
    body("starRating")
      .notEmpty()
      .isNumeric()
      .withMessage("Star rating must be a number"),
    body("facilities")
      .notEmpty()
      .isArray()
      .withMessage("Facilities must be an array"),
  ],
  upload.array("imageFiles", 6),
  async (req: Request, res: Response) => {
    console.log("req body");
    console.log(req.body);
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res
        .status(400)
        .json({ message: "Bad Request", errors: errors. array() });
    }
    try {
      const files = req.files as Express.Multer.File[];
      const promises = files.map(async (file) => {
        const fileExt = mime.extension(file.mimetype);
        console.log(file);
        // const fileName = file.originalname;
        if (!fileExt) {
          throw new Error("Invalid file type");
        }

        const newFileName = `${Date.now()}`;

        const params = {
          Bucket: process.env.S3_BUCKET as string,
          Key: `${Date.now()}.${fileExt}`,
          Body: file.buffer,
          ContentType: file.mimetype,
        };
        await client.send(new PutObjectCommand(params));
        const link = `https://${process.env.S3_BUCKET_NAME}.${process.env.S3_REGION}.amazonaws.com/${newFileName}`;
        return link;
      });
      const imageUrls = await Promise.all(promises);

      const newHotel: HotelType = req.body; //some of the fields will already be filled by the req body
      newHotel.imageUrls = imageUrls;
      newHotel.lastUpdated = new Date();
      newHotel.userId = req.userId; //this is taken from the auth token

      //save the hotel to the database
      const hotel = new Hotel(newHotel);
      await hotel.save();
      res.status(201).send(hotel); //201 is the status code for created

      res.status(201).json({ message: "Images uploaded successfully" });
    } catch (error) {
      console.log("error creating hotel", error);
      res.status(500).json({ message: "Internal server error" });
    }
  }
);

export default router;

现在,当我提交表单时,我收到以下错误:

错误请求-错误:

0: {type: "field", msg: "Name is required", path: "name", location: "body"}
1: {type: "field", msg: "City is required", path: "city", location: "body"}
2: {type: "field", msg: "Country is required", path: "country", location: "body"}
3: {type: "field", msg: "Description is required", path: "description", location: "body"}
4: {type: "field", msg: "Type is required", path: "type", location: "body"}
5: {type: "field", msg: "Invalid value", path: "pricePerNight", location: "body"}
6: {type: "field", msg: "Price per night must be a number", path: "pricePerNight", location: "body"}
7: {type: "field", msg: "Invalid value", path: "adultCapacity", location: "body"}
8: {type: "field", msg: "Adult capacity must be a number", path: "adultCapacity", location: "body"}
9: {type: "field", msg: "Invalid value", path: "childCapacity", location: "body"}
10: {type: "field", msg: "Child capacity must be a number", path: "childCapacity", location: "body"}
11: {type: "field", msg: "Invalid value", path: "starRating", location: "body"}
12: {type: "field", msg: "Star rating must be a number", path: "starRating", location: "body"}
13: {type: "field", msg: "Invalid value", path: "facilities", location: "body"}
14: {type: "field", msg: "Facilities must be an array", path: "facilities", location: "body"}

我的标题中的内容类型设置为application/json; charset=utf-8.

这是请求的有效负载:

name: My Hotel
city: Iwdj
country: Pdihuf
description: poiuytrewqasdfghjkllllllllllllllllkmnbvcxz
type: hotel
pricePerNight: 7
starRating: 3
adultCapacity: 8
childCapacity: 7
facilities[0]: free parking
facilities[1]: swimming pool
imageFiles: (binary)
imageFiles: (binary)

我try 手动将内容类型设置为multipart/formdata,但随后出现错误

多部分:找不到边界

推荐答案

因为请求是multipart/form-data内容类型,所以Express验证器不能处理它,因为它在Multer处理请求之前运行,所以它收到空正文,因此每个验证都失败(它可能试图以JSON的形式处理请求,但不确定JSON头来自哪里,但当您稍后登录req.body时,它似乎已经被Multer处理了(您可以将验证器移动到单独的中间件,这样它就不会到达路由处理程序/下一个中间件,请参见:Example: creating own validation runner).

因此,将Multer中间件移到快速验证器中间件之前,这样它就会收到已处理的body个对象(前面的请求看起来很好,不需要设置内容类型,它是自己处理的,边界错误是try 手动设置时得到的):

router.post(
  "/",
  verifyToken,

  //  multer needs to process request first to obtain req.body
  upload.array("imageFiles", 6),

  [
    body("name").notEmpty().withMessage("Name is required"),
    //...
  ],
  async (req: Request, res: Response) => {
    console.log("req body");
    console.log(req.body);
    

Node.js相关问答推荐

链接Inbox类方法,范围在哪里以及为什么发生变化?

如何使用多个OR参数从多个集合聚合

当变量在另一个文件中初始化时,在初始化错误之前无法访问变量

验证器功能在mongoose 中不起作用

从mongodb集合中获取每分钟数据的每小时数据

使用 Google Drive API 按文件夹 ID 检索文件夹的内容

如何模拟 mysql2 `getConnection`

如何使用Stripe测试失败的收费?

如果我在父文件夹中运行,子进程生成不起作用

bcrypt.compare 每次都返回 false

使用react 组件加载特定 DIV 而无需重新加载整个页面

AWS EC2 npm install 突然很慢

Web3.js 脚本在监听 CreatedPairs 时退出

NodeJS为exec设置环境变量

按日期时间字段获取最新的 MongoDB 记录

从 zip 文件在 AWS 中创建 lambda 函数

如何仅在丢失的路由上将 Express.js 设置为 404?

Node.js:如何附加到正在运行的进程并使用控制台调试服务器?

#!/bin/env是什么意思(在 node.js 脚本的顶部)?

如何从 find 方法返回 Mongoose 结果?