axios: Can't get a .post with 'Content-Type': 'multipart/form-data' to work

I’ve spent a few hours today trying to get a post request to work with a few parameters and a file that I need to upload.

I was able to make it work with pure javascript and XMLHttpRequest but it doesn’t work with Axios. What am I doing wrong?

Here’s the code that works using XMLHttpRequest:

let data = new FormData();

data.append('action', 'ADD');
data.append('param', 0);
data.append('secondParam', 0);
data.append('file', new Blob([payload], { type: 'text/csv' }));

// this works
let request = new XMLHttpRequest();
request.open('POST', url);
request.send(data);

What would be the ‘Axios’ version of that?

Here’s one of my tries (the simple one):

// this won't work
const config = { headers: { 'Content-Type': 'multipart/form-data' } };
    axios.post(url, data, config)
    .then(response => console.log(response))
    .catch(errors => console.log(errors));

Thank you! And thanks for your great work with Axios!

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 144
  • Comments: 99 (9 by maintainers)

Most upvoted comments

@rafaelbiten I’ve just tried to reproduce the issue but to no avail. I used the following code:

const data = new FormData();

data.append('action', 'ADD');
data.append('param', 0);
data.append('secondParam', 0);
data.append('file', new Blob(['test payload'], { type: 'text/csv' }));

axios.post('http://httpbin.org/post', data);

The data was successfully sent to the server:

screen shot 2016-05-12 at 9 12 19 pm

Two years latter: Same problem…

This is definitely working for me—all browsers, including Safari iOS.

My code is something like this:

function samplePost (config) {

// save reference this

let that = this;



// can optionally pull in form fields from an existing HTML form)

let myForm = document.getElementById('myForm');

let myFormData = new FormData(myForm);



// add in data from config.data if applicable

if (config && config.data) {

    that.objToStr(config.data, '', myFormData);



    for (let n2 in config.data) {

        if (config.data.hasOwnProperty(n2)) {

            myFormData.set(n2, config.data[n2]);

        }

    }

}



if (config.binaryFiles && config.binaryFiles.length > 0) {



    for (let i = 0; i < config.binaryFiles.length; i = i + 1) {

        let thisFile = config.binaryFiles[i];

        myFormData.append(thisFile.fieldName, thisFile.binaryData, thisFile.fileName)

    }

}





let axiosConfig = {

    method: 'post',

    url: config.url,

    data: myFormData,



    onUploadProgress: config.onUploadProgress,

};



if (config && config.binaryFiles && config.binaryFiles.length > 0) {

    axiosConfig.headers = {'Content-Type': 'multipart/form-data'};

}

else {

    axiosConfig.headers = {'Content-Type': 'application/x-www-form-urlencoded'};

}



const ax = axios.create();

// note that passing in config to the constructor is broken as of axios v0.19.0-beta.1

// So we work around by passing in config to the request() method



ax.request(axiosConfig)

    .then(function (response) {

        // handle success



        alert(response.data);

        

    })

};

// call samplePost to upload

samplePost({

url: 'async',

data: {somefield: 'some value'}, //note: passes in as form fields



// optionally include array of binary files

binaryFiles: thisFileList

});

From: Antonio Vázquez notifications@github.com Sent: Tuesday, September 11, 2018 11:23 AM To: axios/axios axios@noreply.github.com Cc: DavidRueter drueter@assyst.com; Comment comment@noreply.github.com Subject: Re: [axios/axios] Can’t get a .post with ‘Content-Type’: ‘multipart/form-data’ to work (#318)

4 hours and counting to make a post request from Safari. Still not happening… what the hell guys ??

None of the solutions here worked from me… 😦

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/axios/axios/issues/318#issuecomment-420371510 , or mute the thread https://github.com/notifications/unsubscribe-auth/AFbi6JQBv06LTwL4z3HIAlvXAXDyps1-ks5uZ_9wgaJpZM4Ibm_z . https://github.com/notifications/beacon/AFbi6BSPfwPvNaWPFSdvtLKRYXS1m4uKks5uZ_9wgaJpZM4Ibm_z.gif

just add boundary to Content-Type:

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

let data = new FormData();
data.append('file1', fs.createReadStream('./image1.jpeg'), 'image1.jpeg');
data.append('file2', fs.createReadStream('./image2.jpeg'), 'image2.jpeg');

let options = {
    method: 'POST',
    url: 'http://localhost:3200/upload',
    headers: {
        'Content-Type': `multipart/form-data; boundary=${data._boundary}`
    },
    data
};

return request(options)
    .then(response => {
        console.log(response);
    });

@demeter-macik thanks, adding boundary worked for me 😄

    const form = new FormData();
    form.append('email', 'test2@pay-mon.com');
    form.append('phone_no', '63');
    form.append('phone_code', '9179303100');

    if (logo) {
      form.append('logo', logo);
    }

    const response = await axios({
      method: 'post',
      url: `${apiUrl}users`,
      data: form,
      headers: {
        'content-type': `multipart/form-data; boundary=${form._boundary}`,
      },
    });

If anyone is wondering, here’s an example how to use FormData with axios. You basically have to stream the data into a buffer and pass the correct headers.

const concat = require("concat-stream")
const fd = new FormData()

fd.append("hello", "world")
fd.append("file", fs.createReadStream(file))
fd.pipe(concat(data => {
  axios.post("/hello", data, {
    headers: fd.getHeaders()
  })
}))

@krzkaczor Try adding in the content-type if you have not done so already

const config = { headers: { 'Content-Type': 'multipart/form-data' } };
let fd = new FormData();
fd.append('file',files[0])
return axios.post("http://localhost:5000/upload", fd, config)

Please reopen until there is some consistent answer/workflow for this. It seems like a lot of people are still experiencing issues with this.

@nickuraltsev this is a minimal example that doesn’t work on node:

const data = new FormData();

data.append('action', 'ADD');
data.append('param', 0);
data.append('secondParam', 0);

axios.post('http://httpbin.org/post', data).then(req => {
  console.log('Req done: ', req)
}).catch(err => {
  console.error('Error: ', err)
})

Error: write after end

@Sreekhar Set Content-Type to undefined to let browser change it to multipart/form-data and add boundary automatically

@Sreekhar I don’t know if it will work, but could you maybe add the FormData as the second argument instead of wrapping it in another object? axios.post('/dataAPI/sendFile', fd, config)

If you need to use ‘UploadCommand’ as the name of the part where the file is, you need to use this fd.append('UploadCommand', this.refs.multipartfiles.files[0]);

Hi @nickuraltsev , I’m getting the same issue.

      var fd = new FormData();
      fd.append('file', this.refs.multipartfiles.files[0]);

            const config = { headers: { 'Content-Type': 'multipart/form-data' } };
            axios.post('/dataAPI/sendFile', {
                "UploadCommand": fd
              }, config)
              .then(function (response) {
                console.log(response);
              })
              .catch(function (error) {
                console.log(error);
              });

Please find the screen shot of my header information below,

image

I have a question, does axios support sending multi-part data files to node server?

this worked:

axios.post(localhost:3000/items, formData, { headers: { ‘Content-Type’: ‘multipart/form-data’ }});

@guncha Your example worked for me in 0.15.3, until I tried to upload a binary file, which ended up encoded as UTF8. Telling concat to use a buffer fixed the issue.

const concat = require("concat-stream")
const fd = new FormData()

fd.append("hello", "world")
fd.append("file", fs.createReadStream(binaryFile))
fd.pipe(concat({encoding: 'buffer'}, data => {
  axios.post("/hello", data, {
    headers: fd.getHeaders()
  })
}))

I tried different solutions but in the end I handled this issue adding the headers:

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

const form = new FormData()
form.append('foo', 'bar')

await axios.post('http://myserver', form, { headers: form.getHeaders() })

this worked for me too, thanks @arvi

twiliosms = async (Codigo) => {

var FormData = require(‘form-data’); var fs = require(‘fs’);

var form = new FormData(); form.append(‘To’, ‘+524772773737’); form.append(‘From’, ‘+737373737’); form.append(‘Body’, Codigo);

try { let axapi = await axios( { url: ‘2010-04-01/Accounts/AC8aa53c907943af79234414bb725c2cd3/Messages.json’, baseURL: ‘https://api.twilio.com’, headers: {‘content-type’: multipart/form-data; boundary=${form._boundary},}, data: form, auth: { username: ‘AC8aa53c907943af79234414bb725c2cd3’, password: ***, }, method: ‘post’, } )

} catch (e) {console.error(e)} }

+1 reopen

for me , this works:

let formData = new FormData(document.querySelector('#form'));

axios.post("/api/xxx", formData).then(console.log).catch(console.error)

and this won’t work

let formData = new FormData(document.querySelector('#form'));

axios.post("/api/xxx", {data: formData}).then(console.log).catch(console.error)

be aware of the postdata param format should be (url , FormData), not (url, {data: FormData})

Also when using buffers to represent file, this worked for me:

      const form = new FormData();
      const fileBuffer = new Buffer(
        'MM2 - noticeably shallower than the original - score: 101%', 'utf-8'
      );
      form.append('name', 'reviews.txt'); // additional form data field
      form.append('file', fileBuffer, 'original-file-name.bar');

      const res = await axios.post(`/uploadfile`, form, { headers: form.getHeaders() });

Hi @Sreekhar For me I changed config to const config = { headers: { 'Content-Type': 'application/json' } }; and it worked fine

@Googrosh Yes. Yes. Yes.

Spent half a day figuring out whether it is related to client or server config. At the end, headers: form.getHeaders() did the trick.

I’m wandering this library still require self-written workarounds for form data posts…

I agree with @epferrari, please consider reopen this issue. It’s ok to send a base64 string with FormData in chrome, but just can’t get it done with axios in node(v8.9.3). And it works with node-fetch…

const fetch = require('node-fetch')
const axios = require('axios')
const FormData = require('form-data')
const base64Img = require('base64-img')

const b64 = base64Img.base64Sync('./test.jpg').split('base64,')[1]
const form = new FormData()
form.append('b64_data', b64)
const headers = form.getHeaders()

// with node-fetch it worked
fetch('http://some.url', {
  method: 'POST',
  body: form,
  headers,
}).then(res => res.text()).then(console.log).catch(console.log)

// not working with axios
axios({
  method: 'POST',
  url: 'http://some.url',
  data: form,
  headers,
}).then(console.log).catch(console.log)

=== update === I don’t understand, I use the same headers for node-fetch and axios, and it seems that they post the same form data to server, how come they end up differently? By the way, the real url which I’m posting comes from here, what I’m doing is mock the browser’s http request with nodejs, to send a image to server and get a link back.

This may not be on point, but the issue might be related to using body-parser on the server side. I was struggling with a similar issue and ran across this post:

https://philna.sh/blog/2016/06/13/the-surprise-multipart-form-data/

TL;DR - body-parser doesn’t handle multipart/form-data. In other words, axios isn’t the problem and body-parser is. This might be why the buffer solutions mentioned above work.

I assume this functionality is for security reasons, as noted here:

http://andrewkelley.me/post/do-not-use-bodyparser-with-express-js.html

I hope that helps someone!

Alternatively, I would use a promise:

const promise = new Promise((resolve) => {
  const fd = new FormData();
  fd.append("hello", "world");
  fd.append("file", fs.createReadStream(binaryFile));
  fd.pipe(concat({ encoding: 'buffer' }, data => resolve({ data, headers: fd.getHeaders() })));
});
promise.then(({ data, headers }) => axios.post('/hello', data, { headers }));

@PierreCavalet nope, I used request-promise instead.

To this day, this is not working on nodejs. The request-promise approach also worked for me.

I got around this by using:

<input onChange="emitImageInfo(this)" type="file" multiple>

function emitImageInfo($event){
  let files = $event.target.files
  let formData = new FormData();

  for (let i = 0; i < files.length; i++)
      formData.append('image[' + i + ']', files[i])

  axios.post('file/upload', formData)
     .then((result) => { console.log('got it') })
     .catch((err) => { console.log(err) })
}

I struggled with this a lot longer that I want to admit, so hopefully this helps someone. I am using axios, express, and express-fileupload. I can successfully upload to Node with params I have appended to the FormData. I pick up the files with req.files and I pick up the rest of the form data with req.body[‘yourfilename’]

Server (Express):

screen shot 2018-03-27 at 1 59 08 pm

router.post('/helper/amazon/upload', function(req, res) { if (!req.files) { return res.status(400).send('No files were uploaded.') } console.log(req.body.filename); return console.log(req.files);

Front-end (axios)

screen shot 2018-03-27 at 1 58 45 pm

const formData = new FormData(); formData.append('file', this.validFile); formData.append('filename', 'trails/' + this.$route.params.id.split('-')[0] + '/camping/'); axios.post(/api/helper/amazon/upload, formData, { headers: { 'Content-Type': 'multipart/form-data' } });

Result:

screen shot 2018-03-27 at 2 02 11 pm

Important to note: any of the above solutions do NOT work if you have any default data parameters set in the defaults of the Axios instance. You might also check if you specify a default Content-Type header in your Axios instance (via axios.defaults.headers and axios.defaults.parameters).

HTTP posts that include binary file data seem to work fine in axios v0.16.2

// The following was tested successfully with axios v0.16.2

// Create a new form.  Note:  could also specify an existing form as
// the parameter to the FormData() constructor to copy all the elements
// from the existing form to the new one being created.

var tempFormData = new FormData();

var someNoteValue = 'Hello World';
var someAudioData = [];  // populate this with data from file, with MediaRecorder() etc.


// Add form fields

tempFormData.set('SomeNote', 'Hello World');
tempFormData.set('SomeRecording', someAudioData[0], 'SampleRecording.webm');


// Optional:  output list of form fields to the console for debugging

for (var pair of tempFormData.entries()) {
    console.log('Form field: ' + pair[0] + ', ' + pair[1]);
}


// Call Axios to post the form to myurl

axios({
    method: 'post',
    url: 'myurl',
    data: tempFormData,
    config: { headers: {'Content-Type': 'multipart/form-data' }}
})
    .then(function (response) {
        //handle success
        console.log(response);
    })
    .catch(function (response) {
        //handle error
        console.log(response);
    });

            }

@rrapant The issue with duplicate content type values has been fixed by #317. The fix will be included in the next release. Thank you!

Possibly related header issue. When content-type is set in config object in request it is concatenated e.g. axios.post( ‘https://example.com/login’, {emailAddress: email, password: hashedPassword}, {headers: {‘content-type’: ‘application/json’}} );

header content-type comes in as application/json,application/json body will not be parsed in this case

@Googrosh Brilliant, .getHeaders() got it working for me too. I can’t tell you how many hours I spent on this. Thanks!

Moved to got because it just works with formData and multipart/form-data - https://github.com/sindresorhus/got 🙌 Close, but no cigar Axios 👋

  const form = new FormData()
  const stream = fs.createReadStream(file.path)

  form.append('file', stream, file.name)

  try {
    await got.post('http://example.com', { body: form })
  } catch (error) {
    next(error)
  }

not working with golang

can we get this reopened? Looks like a lot of people are still bumping up against this, including myself. For example, this request doesn’t make it to the server as expected via axios, but if I send the same file over Postman as multipart/form-data, all works.

screen shot 2018-03-26 at 12 22 35 am

Edit: My problem was trying to send a base64 encoded data-uri as form-data. If anyone else is struggling with the same issue, here is some sample code to convert it:

async function importCsv(data: CsvImportData): Promise<void> {
    const formData = new FormData();
    const headers = {'Content-Type': 'multipart/form-data'};

    formData.append('csv', dataURItoFile(data.file, `upload_${Date.now()}.csv`));

    try {
      await axios.post('https://example.com/api/upload/csv', formData, {headers});
    } catch(e) {
      console.error(e);
    }
}

function dataURItoFile(dataURI: string, defaultFileName: string): File {
  let byteString: string;
  const [metadata, data] = dataURI.split(',');
  if (/base64$/.test(metadata)) {
    byteString = atob(data);
  } else {
    byteString = unescape(data);
  }

  const mimetype: string = metadata.split(':')[1].split(';')[0];
  const filename: string = (metadata.match(/name\=(.*);/) || [])[1] || defaultFileName;

  let dataView: Uint8Array = new Uint8Array(byteString.length);
  for (let i = 0; i < byteString.length; i++) {
    dataView[i] = byteString.charCodeAt(i);
  }
  return new File([dataView], filename);
}

@krzkaczor thanks, forced to switch too

@nickuraltsev right! What you see on that screenshot is all I have on dev tools. @rrapant may be right, but I’m almost sure that setting 'Content-Type'or not, at least on this case, wasn’t changing anything. I would have to check again to be sure.

check your axios.create, this headers should “headers:{}” and no use data.like this : var instance = axios.create({ headers: { // ‘Content-Type’: ‘application/x-www-form-urlencoded;charset=UTF-8’, }, // data: {}, params: {} });

hii plz i need helps : i got “file: This value should not be blank.” when i try to fetch post an image using fetch :

handleSubmit = (event) => {
    event.preventDefault();
    //const { category } = this.state;
    console.log(this.state.file)
    let formData = new FormData();
    formData.append("file",this.state.file);
    formData.append("name",this.state.name);
    alert('You Added a new Category Named  ' + this.state.file);
    fetch(`${process.env.REACT_APP_BASE_URL}/category/image`, {
      method: 'POST',
      body: formData
    }).then(res => res.json()).then(err => console.log(err));
  }
``` constructor(props) {
    super(props);

    this.state = {
      
        name: '',
        file: null
      ,
      isLoaded: false,
      isEditMode: false,

    }
    
  }
``` <input type="file" name="file"  onChange={this.handleChange}/>
        <img src={this.state.file}/>

Code works in browser but not on node.

const fdata = new FormData();
fdata.append('user', u);
fdata.append('hostnames', n.join(' '));
const host = localStorage.getItem('host');
const port = localStorage.getItem('port');
axios({
  url: `http://${host}:${port}/hosts/remove`,
  method: 'post',
  data: fdata
}).then(response => {
  if (response.status === 200) {
    console.log(response.data);
    console.log('Removed host successfully');
  }
  return null;
}).catch(er => console.log(er));

@krzkaczor Have you found any work around to send multipart/form-data with axios ?

Closing this for now. Please feel free to reopen if necessary.