为什么我的表单数据在我的 POST 请求中作为 application/json 发送,为什么它返回 Bad Request 错误?

问题描述 投票:0回答:1

我有一个在数据库中添加酒店的表格。我正在使用反应钩子形式。在表单中,我也要求图像作为输入。提交表单后,表单中的数据将转换为表单数据,然后发送到 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:{类型:“字段”,消息:“名称为必填项”,路径:“名称”,位置:“正文”}
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:“无效值”,path:“pricePerNight”,location:“body”}
6: {type: "field", msg: "每晚价格必须是数字", path: "pricePerNight", location: "body"}
7:{类型:“字段”,消息:“无效值”,路径:“adultCapacity”,位置:“body”}
8: {type: "field", msg: "成人容量必须是数字", path: "adultCapacity", location: "body"}
9:{类型:“字段”,消息:“无效值”,路径:“childCapacity”,位置:“body”}
10: {type: "field", msg: "子容量必须是数字", path: "childCapacity", location: "body"}
11:{类型:“字段”,消息:“无效值”,路径:“starRating”,位置:“正文”}
12:{type:“field”,msg:“星级必须是数字”,path:“starRating”,location:“body”}
13:{type:“field”,msg:“无效值”,path:“设施”,位置:“body”}
14:{type:“field”,msg:“设施必须是数组”,path:“设施”,位置:“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)

我尝试手动将内容类型设置为

multipart/formdata
,但随后出现错误

多部分:未找到边界

node.js multipartform-data content-type form-data 400-bad-request
1个回答
0
投票

由于请求是

multipart
格式,express验证器无法处理它,因为它在multer处理请求之前运行,所以它收到空的body,因此每次验证都会失败。

因此,将 multer 中间件移到 Express 验证器中间件之前,以便它接收已处理的

body
对象:

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);
    
© www.soinside.com 2019 - 2024. All rights reserved.