Javascript 无法从React.js将图像发布到我的API路由
我正在创建一个MERN应用程序,在该应用程序中,我创建了一个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
/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中工作,您就可以开始逐个删除东西,看看是什么导致了问题。你看到了吗?