I want to upload an article with file. When I set into my request:
headers: {
"Content-Type": "multipart/form-data",
"token": `Bearer ${token}`
},
then I get this Error:
Multipart: Boundary not found.
I have read, that I should not set the Content-Type in my axios-request, but when I do this, I get the 403 error out of my backend. I tried to append all fields in FormData, but I am getting the above error either. I have googled "Boundaries" in axios and tried it with "getHeaders()", but then the console says "getHeaders()" is not a function.
That is my frontend code:
const [formdata, setFormdata] = useState(
{
ressort:"",
theme:"",
title:"",
content:"",
}
)
const {ressort,theme,title,content} = formdata;
const [fileData, setFileData] = useState({
img:""
})
const {img} = fileData;
const fileInput = useRef(img);
const fileChange = (e)=>{
console.log(fileInput.current.files);
setFileData(fileInput.current.files[0])
}
console.log(fileData); //works
const handleChange = (e)=>{
setFormdata((prevState)=>({
...prevState,
[e.target.name]: e.target.value
}))
}
const onSubmit = (e)=>{
e.preventDefault();
const data = new FormData();
data.append("img", fileData);
data.append("ressort", formdata.ressort);
data.append("theme", formdata.theme);
data.append("title", formdata.title);
data.append("content", formdata.content)
console.log(data);
const mainnewsData ={
data,
}
console.log(mainnewsData);
dispatch(createMainNews(mainnewsData));
}
Here is my redux service:
const API_URL = "http://localhost:5000/api/mainNews/";
const createMainNews = async (mainnewsData, token)=>{
const config = {
headers: {
token: `Bearer ${token}`,
'Content-Type': `multipart/form-data;`,
},
// transformRequest: (data, error) => { //gives 403
// return mainnewsData;
// }
}
const response = await axios.post(API_URL, mainnewsData, config);
return response.data;
}
Here is my backend:
router.post("/", upload.single("img"), verifyTokenAndAuthorization, async (req,res)=>{
const newMainNews = new MainNews({
img: req.file.originalname,
ressort: req.body.ressort,
theme: req.body.theme,
title: req.body.title,
content:req.body.content,
});
console.log(newMainNews);
try{
const savedMainNews = await newMainNews.save();
res.status(200).json(savedMainNews);
} catch(error){
res.status(403)
throw new Error("Action failed");
}
});
That is my multer-storage:
const multer = require("multer");
const storage = multer.diskStorage({
destination:(req,file, callback)=>{
callback(null, '../../frontside/public/uploads/')
},
fileName: (req, file, callback)=>{
callback(null, Date.now()+ "--"+ file.originalname)
}
})
const upload = multer({storage:storage});
module.exports = upload;
I found out the solution by myself. Here is some code you can work with. The Frontend:
const MainNews = () => {
const { mainnews, isLoading, isError, message} = useSelector((state)=>state.mainnews);
const dispatch = useDispatch();
useEffect(()=>{
if(isError){
window.alert(message);
}
dispatch(getAllMainNews());
return ()=>{
dispatch(reset());
}
}, [dispatch, isError, message]);
//text
const [formdata, setFormdata] = useState(
{
ressort:"",
theme:"",
title:"",
content:"",
}
)
const {ressort,theme,title,content} = formdata;
//file
const [fileData, setFileData] = useState({
img:""
})
const {img} = fileData;
const fileInput = useRef(img);
//change and preview
const [preview, setPreview] = useState("");
const fileChange = (e)=>{
const file = fileInput.current.files[0];
setFileData(file);
handlePreview(file)
}
const handlePreview = (file)=>{
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = ()=>{
setPreview(reader.result);
}
}
console.log(fileData); //works
//text
const handleChange = (e)=>{
setFormdata((prevState)=>({
...prevState,
[e.target.name]: e.target.value
}))
}
const onSubmit = (e)=>{
e.preventDefault();
const mainnewsData = new FormData();
mainnewsData.append("ressort", formdata.ressort);
mainnewsData.append("theme", formdata.theme);
mainnewsData.append("title", formdata.title);
mainnewsData.append("content", formdata.content);
mainnewsData.append("img", fileData);
for(let value of mainnewsData){
console.log(value);
}
dispatch(createMainNews(mainnewsData));
}
http-request in my redux-service:
const createMainNews = async (mainnewsData, token)=>{
const config = {
headers: {
// 'Content-Type': `multipart/form-data`,
'Content-Type' : 'application/json',
token: `Bearer ${token}`,
},
}
const response = await axios.post(API_URL, mainnewsData, config);
console.log(response);
return response.data;
}
multer:
const storage = multer.diskStorage({
destination:(req,file, callback)=>{
callback(null, path.resolve(process.cwd(), 'frontside/public/uploads'));
},
fileName: (req, file, callback)=>{
callback(null, Date.now()+ "--"+ path.extname(file.originalname));
}
})
const upload = multer({storage:storage});
module.exports = upload;
Don't forget in your index.js:
app.use(express.static(path.resolve(process.cwd(), 'frontside/public/')));
And the backend mongoose Schema:
const MainnewsSchema = new mongoose.Schema({
img:{type:String, required:true},
cloudinary_id:{type:String, required:true},
ressort:{type:String, required:true},
theme:{type:String, required:true},
title:{type:String, required:true},
content:{type:String, required:true},
clicked:{type:Number, default:0},
},
My backend:
router.post("/", upload.single("img"), verifyTokenAndAuthorization, async (req,res)=>{
// const {img, cloudinary_id, ressort, theme, title, content} = req.body;
try{
const uploadResult = await cloudinary.uploader.upload(req.file.path,{
upload_preset: "Mern_redux-practice",
resource_type: "auto",
});
// console.log("Upload successfull", JSON.stringify(uploadResult, null, 2));
const newMainNews = new MainNews({
cloudinary_id : uploadResult.public_id,
ressort: req.body.ressort,
theme: req.body.theme,
title: req.body.title,
content: req.body.content,
img: uploadResult.secure_url,
});
console.log(newMainNews);
const savedMainNews = await newMainNews.save();
res.status(200).json(savedMainNews);
} catch(error){
res.status(403)
throw new Error("Action failed");
}
});