Search code examples
node.jsaxiosmultipartform-databody-parser

nodejs bodyparser gives truncated value for string sent from axios using formdata


We are using axios on the client(browser) side with formdata to send requests to the nodejs server. The nodejs server uses bodyparser along with express-fileupload for file uploads. The request sends meta data (json) to the server in string format. bodyparser on the server is set to 100mb for both json and urlencoded. Axios is setting the content-type to "multipart/form-data". This setup is working fine when the string size is less than 1mb. The problem arises when the string(meta) size increases more than 1mb, the server receives a truncated value of the meta. JSON parsing throws "Unexpected end of JSON input at JSON.parse". Nginx is used for routing to the nodejs server. client_max_body_size on Nginx is set for 500M. Here is the client code sample

let fd = new FormData()
fd.append('uid',1);
fd.append('meta',"json string here");
axios({url:'http://localhost:9090/receivemeta',method:'POST',
    data: fd
}).then(resp=>{console.log(resp.data);}).catch(error=>{console.error(error.response.data)});

The server side is as follows

app.post('/receivemeta',async(req,res)=>{
   try{
      let meta = JSON.parse(req.body.meta);
      fs.writeJSONSync('/tmp/meta.json',meta,'utf-8');
      res.json({success:true})
   }catch(error){res.json({success:false,error:error});
})

Is bodyparser the issue here for failing with string data greater than 1mb?


Solution

  • body-parser is not used at all for multipart/form-data requests.

    The middleware handling your request body data in this case is express-fileupload which in turn uses Busboy.

    The default limit for field size is 1MB.

    Any size limits for fields should be configured along side file size limits

    app.use(fileUpload({
      limits: {
        fileSize: 100 * 1024 * 1024,
        fieldSize: 5 * 1024 * 1024, // 👈 5MB
      },
    }));
    

    Unless you're uploading files, I would recommend you avoid FormData and stick to application/json requests

    axios.post("/receivemeta", {
      uid: 1,
      meta: {
        // whatever data here as a plain object, not JSON
      },
    }, {
      baseURL: "http://localhost:9090/", // easier to set via env
    });
    

    and on the server-side, provided you've used the express.json() middleware...

    const { meta, uid } = req.body;