Javascript 无法从React.js将图像发布到我的API路由

Javascript 无法从React.js将图像发布到我的API路由,javascript,node.js,reactjs,axios,multer,Javascript,Node.js,Reactjs,Axios,Multer,我正在创建一个MERN应用程序,在该应用程序中,我创建了一个api路由/api/books,用户可以将书籍的详细信息与图像一起发布,数据将存储在MongoDB中。 我使用的是multer,它将编码后的图像以二进制格式存储在数据库中 当我用postman测试它时,我工作得非常好,数据被添加到数据库中,我收到响应200状态 但我在将数据从react前端发送到api时遇到了问题,我创建了受控表单并将数据值存储在状态中,然后我调用函数在使用axios提交表单时将数据发布到api,但我在终端中发现错误M

我正在创建一个MERN应用程序,在该应用程序中,我创建了一个api路由
/api/books
,用户可以将书籍的详细信息与图像一起发布,数据将存储在MongoDB中。
我使用的是
multer
,它将编码后的图像以二进制格式存储在数据库中

当我用postman测试它时,我工作得非常好,数据被添加到数据库中,我收到响应200状态

但我在将数据从react前端发送到api时遇到了问题,我创建了受控表单并将数据值存储在状态中,然后我调用函数在使用axios提交表单时将数据发布到api,但我在终端中发现错误
Multipart:Boundary not found
,我认为文件没有正确地通过axios发送

反应表单页面:

// states
  const [data, setData] = useState({
    book_name: "",
    book_author: "",
    for_branch: "",
    for_semester: "1",
  });
  const [file, setFile] = useState(null);
  
// to POST data onSubmit
  const handleSubmit = async (e) => {
    e.preventDefault();
    setAddError("");

    if (!file) {
      setAddError("Add Book Image");
      return;
    } else if (file.size > 1000000) {
      setAddError("Use Images less than 1MB");
      return;
    } else if (
      !data.book_name ||
      !data.book_author ||
      !data.for_branch ||
      !data.for_semester
    ) {
      setAddError("Add All Details");
      return;
    }

    await addBook(data, file);
    toggleNotification();
  };

// Form 
      <Form
        onSubmit={handleSubmit}
        className="form"
        encType="multipart/form-data"
      >
        <Col className="image">
          <Form.Group>
            <Form.File
              id="exampleFormControlFile1"
              label="Upload Book Image"
              onChange={onFileChange}
              style={{ margin: "auto" }}
            />
            {file ? (
              <div>
                <h5>File Name: {file.name}</h5>
                <h5>Last Modified: {file.lastModifiedDate.toDateString()}</h5>
              </div>
            ) : (
              <h5>Choose before Pressing the Upload button</h5>
            )}
            <hr />
          </Form.Group>
        </Col>
        <Col md={6} className="book-details">
          {addError !== "" && (
            <Alert variant="danger">
              <FaInfoCircle /> {addError}
            </Alert>
          )}
          <Form.Group controlId="exampleForm.ControlInput1">
            <Form.Control
              type="text"
              className="custom-input"
              placeholder="Enter book name"
              name="book_name"
              value={data.book_name}
              onChange={handleChange}
            />
          </Form.Group>
          <Form.Group controlId="exampleForm.ControlInput2">
            <Form.Control
              type="text"
              className="custom-input"
              placeholder="Enter book author name"
              name="book_author"
              value={data.book_author}
              onChange={handleChange}
            />
          </Form.Group>
          <Form.Group controlId="exampleForm.ControlInput3">
            <Form.Control
              type="text"
              className="custom-input"
              placeholder="Enter branches names"
              name="for_branch"
              value={data.for_branch}
              onChange={handleChange}
            />
          </Form.Group>
          <Form.Group controlId="exampleForm.ControlSelect2">
            <Form.Control
              as="select"
              className="custom-select"
              name="for_semester"
              onChange={handleChange}
            >
              <option default disabled>
                select semester
              </option>
              <option>1</option>
              <option>2</option>
              <option>3</option>
              <option>4</option>
              <option>5</option>
              <option>6</option>
              <option>7</option>
              <option>8</option>
            </Form.Control>
          </Form.Group>
          <Button variant="success" type="submit">
            Add Book
          </Button>
        </Col>
      </Form>

  const addBook = async (formData, file) => {
    dispatch({ type: SEND_LOADING });
    formData = {
      ...formData,
      book_image: file,
    };

    console.log("data from form", formData);
    const res = await axios.post(
      "http://localhost:5000/api/books",
      formData,
      imageHeaderConfig()
    );
    const item = await res.data;

    if (res.status !== 200) {
      console.log("error geting sell books");
      dispatch({ type: SENT_DETAILS, payload: null });
      return;
    }

    console.log(item);
    dispatch({ type: SENT_DETAILS, payload: item });
  };

  const imageHeaderConfig = () => {
    const token = localStorage.getItem("token");
    const config = {
      headers: {
        "Content-Type": "multipart/form-data",
        Accept: "application/json",
        type: "formData",
      },
    };

    if (token) config.headers["x-auth-token"] = token;
    console.log(config);
    return config;
  };
const express = require("express"),
  multer = require("multer"),
  image = multer({
    limits: {
      fileSize: 1000000,
    },
    // storage: multer.memoryStorage(),
    fileFilter(req, file, cb) {
      if (!file.originalname.match(/\.(jpg|png|JPG|PNG|JPEG|jpeg)$/))
        return cb(new Error("Not a valid file format!"));
      cb(undefined, true);
    },
  }),
  router = express.Router();

router.post(
  "/",
  auth,
  image.single("book_image"),
  async (req, res) => {
    console.log(req.user);
    console.log(req.body);
    console.log(req.file);

    const newBook = new Book({
      book_image: req.file.buffer,
      added_by: {
        id: req.user.id,
        name: req.user.name,
      },
      book_name: req.body.book_name,
      book_author: req.body.book_author,
      for_branch: req.body.for_branch,
      for_semester: req.body.for_semester,
      sold: req.body.sold,
    });
    newBook.save().then((book) => {
      res.json(book);
    });
  },
  (err, req, res, next) => {
    console.log(err.message);
    res.status(400).json(err.message);
  }
);

Api代码:

// states
  const [data, setData] = useState({
    book_name: "",
    book_author: "",
    for_branch: "",
    for_semester: "1",
  });
  const [file, setFile] = useState(null);
  
// to POST data onSubmit
  const handleSubmit = async (e) => {
    e.preventDefault();
    setAddError("");

    if (!file) {
      setAddError("Add Book Image");
      return;
    } else if (file.size > 1000000) {
      setAddError("Use Images less than 1MB");
      return;
    } else if (
      !data.book_name ||
      !data.book_author ||
      !data.for_branch ||
      !data.for_semester
    ) {
      setAddError("Add All Details");
      return;
    }

    await addBook(data, file);
    toggleNotification();
  };

// Form 
      <Form
        onSubmit={handleSubmit}
        className="form"
        encType="multipart/form-data"
      >
        <Col className="image">
          <Form.Group>
            <Form.File
              id="exampleFormControlFile1"
              label="Upload Book Image"
              onChange={onFileChange}
              style={{ margin: "auto" }}
            />
            {file ? (
              <div>
                <h5>File Name: {file.name}</h5>
                <h5>Last Modified: {file.lastModifiedDate.toDateString()}</h5>
              </div>
            ) : (
              <h5>Choose before Pressing the Upload button</h5>
            )}
            <hr />
          </Form.Group>
        </Col>
        <Col md={6} className="book-details">
          {addError !== "" && (
            <Alert variant="danger">
              <FaInfoCircle /> {addError}
            </Alert>
          )}
          <Form.Group controlId="exampleForm.ControlInput1">
            <Form.Control
              type="text"
              className="custom-input"
              placeholder="Enter book name"
              name="book_name"
              value={data.book_name}
              onChange={handleChange}
            />
          </Form.Group>
          <Form.Group controlId="exampleForm.ControlInput2">
            <Form.Control
              type="text"
              className="custom-input"
              placeholder="Enter book author name"
              name="book_author"
              value={data.book_author}
              onChange={handleChange}
            />
          </Form.Group>
          <Form.Group controlId="exampleForm.ControlInput3">
            <Form.Control
              type="text"
              className="custom-input"
              placeholder="Enter branches names"
              name="for_branch"
              value={data.for_branch}
              onChange={handleChange}
            />
          </Form.Group>
          <Form.Group controlId="exampleForm.ControlSelect2">
            <Form.Control
              as="select"
              className="custom-select"
              name="for_semester"
              onChange={handleChange}
            >
              <option default disabled>
                select semester
              </option>
              <option>1</option>
              <option>2</option>
              <option>3</option>
              <option>4</option>
              <option>5</option>
              <option>6</option>
              <option>7</option>
              <option>8</option>
            </Form.Control>
          </Form.Group>
          <Button variant="success" type="submit">
            Add Book
          </Button>
        </Col>
      </Form>

  const addBook = async (formData, file) => {
    dispatch({ type: SEND_LOADING });
    formData = {
      ...formData,
      book_image: file,
    };

    console.log("data from form", formData);
    const res = await axios.post(
      "http://localhost:5000/api/books",
      formData,
      imageHeaderConfig()
    );
    const item = await res.data;

    if (res.status !== 200) {
      console.log("error geting sell books");
      dispatch({ type: SENT_DETAILS, payload: null });
      return;
    }

    console.log(item);
    dispatch({ type: SENT_DETAILS, payload: item });
  };

  const imageHeaderConfig = () => {
    const token = localStorage.getItem("token");
    const config = {
      headers: {
        "Content-Type": "multipart/form-data",
        Accept: "application/json",
        type: "formData",
      },
    };

    if (token) config.headers["x-auth-token"] = token;
    console.log(config);
    return config;
  };
const express = require("express"),
  multer = require("multer"),
  image = multer({
    limits: {
      fileSize: 1000000,
    },
    // storage: multer.memoryStorage(),
    fileFilter(req, file, cb) {
      if (!file.originalname.match(/\.(jpg|png|JPG|PNG|JPEG|jpeg)$/))
        return cb(new Error("Not a valid file format!"));
      cb(undefined, true);
    },
  }),
  router = express.Router();

router.post(
  "/",
  auth,
  image.single("book_image"),
  async (req, res) => {
    console.log(req.user);
    console.log(req.body);
    console.log(req.file);

    const newBook = new Book({
      book_image: req.file.buffer,
      added_by: {
        id: req.user.id,
        name: req.user.name,
      },
      book_name: req.body.book_name,
      book_author: req.body.book_author,
      for_branch: req.body.for_branch,
      for_semester: req.body.for_semester,
      sold: req.body.sold,
    });
    newBook.save().then((book) => {
      res.json(book);
    });
  },
  (err, req, res, next) => {
    console.log(err.message);
    res.status(400).json(err.message);
  }
);

编辑

正如你们中的一些人建议使用FormData对象 所以我把POST函数改为这个,我仍然有相同的错误
Multipart:Boundary not found

const addBook = async (data, file) => {
    dispatch({ type: SEND_LOADING });

    let formData = new FormData();
    formData.append("book_name", data.book_name);
    formData.append("book_author", data.book_author);
    formData.append("for_semester", data.for_semester);
    formData.append("for_branch", data.for_branch);
    formData.append("book_image", file);

    console.log("data from form", formData);
    const res = await axios.post(
      "http://localhost:5000/api/books",
      formData,
      imageHeaderConfig()
    );
    const item = await res.data;

    if (res.status !== 200) {
      console.log("error geting sell books");
      dispatch({ type: SENT_DETAILS, payload: null });
      return;
    }

    console.log(item);
    dispatch({ type: SENT_DETAILS, payload: item });
  };

您应该使用
FormData
类来正确处理此问题,如所示。

表单数据不仅仅是一个对象。您需要使用
var formData=new formData();formData.append('book\u image',file)我已将数据中的所有键、值对追加到FormData对象,并使用axios发送,但错误仍然相同。我也尝试过删除标题,或者只使用内容类型多部分/表单数据,但仍然存在错误。我已经更新了帖子以显示我所做的更改。如果它在Postman中起作用,我将首先在Axios中复制它(标题、参数等)。一旦它在Axios中工作,您就可以开始逐个删除东西,看看是什么导致了问题。你看到了吗?