Search code examples
reactjsexpressfile-uploadaxiosmulter

(ReactJS, Axios) Posting file to API result in an HTTP request with no payload


I've been stuggling with this problem for several hours now, and as I feel like I browsed all StackOverflow, I therefore am making my first post here, after almost a decade of working in IT ! 😎

Long story short, I have to send a file (an image) to my API (Express 4/Multer), and I am using Axios for that. Below is what the form submit part looks like at the moment :

let avatar = e.target.avatar.files[0];
[...]
if (avatar) {
    let formData = new FormData();
    formData.append("avatar", avatar);
    let customHeaders = {
        
        "Content-Type":
            "multipart/form-data" + ";boundary=xxMyBoundaryxx",
    };
    console.log(avatar); // This is not empty !
    console.log(formData.get('avatar')); // Neither is this !
    axios.post(
        apiUrl,
        formData,
        customHeaders
    );
}

Everything is good server-side, I used Insomnia to test uploading a file to my apiUrl, and it is working like a charm. Also, if I remove my boundary parameter in Content-Type, it triggers an error ('Multipart: Boundary not found').

However, when I post my file using the code above, the resulting HTTP request has no payload, meaning that the data given to my API is empty (checked using Chrome).

I've been trying to understand the problem, and Hope my description was not too vague, and that my english was not too bad 😓

Feel free to reach me if you are missing something to give an answer,

Regards,
Hazreath

PS : Server side "Multipart: boundary not found" error message :

Error: Multipart: Boundary not found
    at new Multipart (C:\Workspace\React\Tricks\back\node_modules\busboy\lib\types\multipart.js:58:11)
    at Multipart (C:\Workspace\React\Tricks\back\node_modules\busboy\lib\types\multipart.js:26:12)
    at Busboy.parseHeaders (C:\Workspace\React\Tricks\back\node_modules\busboy\lib\main.js:71:22)
    at new Busboy (C:\Workspace\React\Tricks\back\node_modules\busboy\lib\main.js:22:10)
    at multerMiddleware (C:\Workspace\React\Tricks\back\node_modules\multer\lib\make-middleware.js:33:16)
    at Layer.handle [as handle_request] (C:\Workspace\React\Tricks\back\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Workspace\React\Tricks\back\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\Workspace\React\Tricks\back\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\Workspace\React\Tricks\back\node_modules\express\lib\router\layer.js:95:5)
    at C:\Workspace\React\Tricks\back\node_modules\express\lib\router\index.js:281:22

Solution

  • The form boundary part and the entire content-type header should not be defined by the user if you use the native FormData encoder.

    Using Axios v0.27.2:

     const formData = new FormData();
     formData.append('avatar', avatar);
    
     axios.post(apiUrl, formData);
    

    Or:

     axios.postForm(apiUrl, {
       avatar
     });
    

    Or you can just submit the entire FileList object

     axios.post(apiUrl, document.querySelector('#fileInput').files);
    

    Playground