Upload article with file in Mern-Stack not works

Viewed 57

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;
2 Answers

I believe you are doing everything fine. But just to make this work out of equation. I would suggest you to change your axios header configuration. I hope it will work

headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
    Accept: 'application/json',
  },

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");
    }
});
Related