Search code examples
node.jsexpressaxiosmulterform-data

How can I make multer parse a client request sent with form-data properly?


I want to transfer data from a client to a server computer where both of them are using Node.js. On client I'm using the libraries axios and form-data. On the server I'm using express and multer...

The client code that I'm using is the following:

const FormData = require('form-data');
const axios = require('axios');

let form = new FormData();
form.append("user", "someuser");

axios({
    method: 'post',
    url: 'http://localhost:9996/data',
    data: form
})
.then(function (response) {
     console.log(response.status);
})
.catch(function (response) {
     console.log(response.status);
});

And the server code is the following:

const express = require('express')
const bodyParser = require('body-parser');
const multer  = require('multer')

const app = express();
const upload = multer();
app.use(bodyParser.urlencoded({extended: true}));

app.post('/data', upload.none(), function (req, res, next) {
    console.log(req.body);
    res.sendStatus(200)
})

const port = 9996;
app.listen(port, () => {
        console.log(`running on port ${port}`)
})
.on('error', function(err) {
        console.log('stopped')
})

This code is functional and I manage to get the form JSON that I have created on the client as a request message on the server. However, the output of my req.body on the server is as the following:

{ '----------------------------926328179431047129531240\r\nContent-Disposition: form-data; name':
   '"user"\r\n\r\nsomeuser\r\n----------------------------926328179431047129531240--\r\n' }

This output is not formatted as a JSON object as I expected. Isn't the parameter upload.none() from multer supposed to parse req.body as a JSON? Does anyone know what I'm getting wrong here and if there's any other parameter that I need to change in order to make the output on req.body to be formatted as a JSON object?


Observation: I know that if I create this JSON manually with const form = {"user":"someuser"} I will have the output as an object on req.body on the server. However, I'm using form-data because on my original code I plan to read a huge file with createReadStream on the client and write it with createWriteStream on the server, and the library form-data is the solution that I found to make axios support streaming of data.


Solution

  • The reason for what you see is that multer only parses the request when content-type header is set to multipart/form-data. You are not setting request headers so the request is send using application/x-www-form-urlencoded, multer ignores it and body-parser do the parsing instead.

    To fix it set headers on your request like this:

    const FormData = require("form-data");
    const axios = require("axios");
    
    let form = new FormData();
    form.append("user", "someuser");
    // form.append("my_buffer", Buffer.alloc(10)); // or actual image
    
    axios({
      method: "post",
      url: "http://localhost:8080/data",
      data: form,
      headers: form.getHeaders()
    })
      .then(function(response) {
        console.log(response.status);
      })
      .catch(function(response) {
        console.log(response.status);
      });