无法 POST 图片到我的 API 从 React.js 路由
Cannot POST image to my API Route from React.js
我正在创建一个 MERN 应用程序,我在其中创建了一个 api 路由 /api/books
,用户可以在其中 POST 一本书的详细信息及其图像,数据将存储在MongoDB.
我正在使用 multer
并将编码后的图像以二进制格式存储在数据库中。
当我用邮递员测试它时,我工作得很好,数据被添加到数据库中,我收到响应 200 状态。
但是我在将数据从 React 前端发送到 api 时遇到了问题,我创建了受控表单并将数据值存储在状态中,然后我将函数调用到 POST使用 axios 提交表单上的数据 api,但我的终端出现错误 Multipart: Boundary not found
,我认为文件未通过 axios 正确发送。
React 表单页面:
// 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>
对POST数据的反应代码:
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;
};
Api代码:
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);
}
);
EDIT
正如你们中的一些人建议使用 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
class 来正确处理此问题,如 所示。
我正在创建一个 MERN 应用程序,我在其中创建了一个 api 路由 /api/books
,用户可以在其中 POST 一本书的详细信息及其图像,数据将存储在MongoDB.
我正在使用 multer
并将编码后的图像以二进制格式存储在数据库中。
当我用邮递员测试它时,我工作得很好,数据被添加到数据库中,我收到响应 200 状态。
但是我在将数据从 React 前端发送到 api 时遇到了问题,我创建了受控表单并将数据值存储在状态中,然后我将函数调用到 POST使用 axios 提交表单上的数据 api,但我的终端出现错误 Multipart: Boundary not found
,我认为文件未通过 axios 正确发送。
React 表单页面:
// 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>
对POST数据的反应代码:
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;
};
Api代码:
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);
}
);
EDIT
正如你们中的一些人建议使用 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
class 来正确处理此问题,如