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

Created on 11 May 2016  ·  99Comments  ·  Source: axios/axios

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!

Most helpful comment

@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

All 99 comments

The code looks good to me. (You don't need to set the Content-Type, but it's not important.) What happens when you try to send a request via axios?

I noticed that setting Content-Type or not doesn't change anything on this case. When I try to send the request with Axios, seems like data goes as an empty string so the backend will respond with an error related to missing parameters.

I was using 0.9.1 but the problem persists on 0.11.0.

Please let me know if there's anything else I can do to help debug this, ok?
Tks @nickuraltsev !

Could you please take a look at how your requests look like in Chrome Dev Tools Network panel and provide a screenshot if possible?

@nickuraltsev see if this helps:

screen shot 2016-05-11 at 2 56 12 pm

I think the Request Headers are wrong.

So there is no Request Payload?

Well, we should have but the data goes as an empty string. I don't know what may be breaking it (considering the code I shared on my first post).

I see. And there is no Request Payload section for your requests in Dev Tools, correct?

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

@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.

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

@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

@rafaelbiten Could you please try to send a request with FromData to http://httpbin.org/post as in my code snippet?

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

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?_

@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]);

@yungpanda I found an alternative for doing that. I guess I'll have to recreate the API now. Anyways I'll try and check if it works, I'll keep the thread updated. Thanks for your reply.

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

@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

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

@PierreCavalet nope, I used request-promise instead.

@krzkaczor thanks, forced to switch too

@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)

@krzkaczor i am also facing the same issue with axios and multipart/form-data. Can you post the gist of the code you used with request-promise.

@dan-boa here u go: https://gist.github.com/krzkaczor/bdbe09d4096b051a3c18387c4ca79a06 It also shows a hack how to send string as file (setting path)

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()
  })
}))

I had the same issue (in the browser, not in node). Turned out it works if you don't set Content-Type header at all and let axios to figure things out (also check if you don't set that header as a default in the axios interceptors too. If you need some defaults for the rest of the API calls, you can make a seperate axios instance for FormData() requests)

I ended up going with request-promise in the node side when trying to upload to another remote server.

I switched over to request-promise for this same reason. Love axios otherwise though!

@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()
  })
}))

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 }));
const callApi = (url, params) => {
  const formData  = new FormData()
  for(let name in params) {
    let param = params[name]
    if (typeof param === 'object') {
      param = JSON.stringify(params[name])
    }
    formData.append(name, param)
  }

  return axios.post(url, formData)
    .then(response => {
      console.log(response)
    })
}

@guncha working for me. thank you

same issue here

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

Hey,
I am get this file in json format can anyone help me how should i convert it into multipart file.
Platform used is java8.
"body": "------WebKitFormBoundaryQsJGeBuR8e9dQ4Pm\r\nContent-Disposition: form-data; name=\"file\"; filename=\"backup prolog.txt\"\r\nContent-Type: text/plain\r\n\r\n%All the Pre-Defined relations\r\nconnected(hira,rohit,father).\r\nconnected(rohit,rakesh,father).\r\nconnected(ram,hira,father).\r\nconnected(kavri,hira,mother).\r\nconnected(hira,kavri,son).\r\nconnected(arun,vinayak,father).\r\nconnected(vinayak,arun,son).\r\nconnected(arun,shashi,husband).\r\nconnected(shashi,arun,wife).\r\nconnected(vinayak,vardaan,brother).\r\nconnected(vardaan,vinayak,brother).\r\nconnected(shashi,vinayak,mother).\r\nconnected(vinayak,shashi,son).\r\n\r\n\r\n\r\nconnected2(X,Y,D) :- connected(X,Y,D).\r\n%connected2(X,Y,D) :- connected(Y,X,D).\r\n\r\nnext_node(Current, Next,R, Path) :-connected2(Current, Next, R),not(member(Next, Path)).\r\n\r\nfunc(how,is,X,related,to,Y):-depth_first(X,Y,[X],P),write(P).\r\n%Procedure to Start the depth_first\r\ndepth_first(Goal, Goal, _, [Goal]).\r\n\r\ndepth_first(Start, Goal, Visited, [Start,is,R,of|Path]) :-next_node(Start, Next_node,R, Visited),depth_first(Next_node, Goal,[Next_node,R|Visited], Path).\r\n\r\n\r\n\r\n\r\n\r\n\r\n------WebKitFormBoundaryQsJGeBuR8e9dQ4Pm--\r\n"
thanks

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));

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

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

+1 reopen

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

            }

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() });

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).

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!

I have the same issue. I use Axios 0.16.2 and sending by XMLHttpRequest works, but not by Axios.

I have basic FormData object:

const formData = new FormData();
formData.append('name', 'textName');

I tried @Janekk's suggestion:

axios({
      method: 'post',
      url,
      withCredentials: true,
      data: { formData },
    })

then @faalkhah's suggestion:

const config = { headers: { 'Content-Type': 'application/json' } };
    axios({
      method: 'post',
      url,
      withCredentials: true,
      data: { formData },
      config,
    })

or @askona's suggestion:

const config = { headers: { 'Content-Type': undefined } };
    axios({
      method: 'post',
      url,
      withCredentials: true,
      data: { formData },
      config,
    })

Request header is application/json and formData is empty.

I don't know how to try @demeter-macik fix, because it seems like it works only in back-end https://stackoverflow.com/a/13454425/968379

hi all,
I have the same problem
my code in client
`

    const url = '/file/uploadTest';
    const formData = new FormData();
    formData.append('file', file);
    formData.append('params1', value);
    formData.append('params2', value2)

    const config = {
        headers: {
            'Content-Type': 'multipart/form-data',
        }
    }
    axios.post(url,formData,config)`

in sails server, i log console req.body
I found, when i call request 10 times, there are about 3 4 times the server does not receive the body (body is empty).
i checked in devtool of chrome, the request still have transmits the file and body in the payload.
I still have not figured out why, but i have a solution

that is request header.

`code

    const url = '/file/uploadTest';
    const formData = new FormData();
    formData.append('file', file);
    formData.append('params1', value);
    formData.append('params2', value2)
    const config = {
        headers: {
            'Content-Type': 'multipart/form-data',
            'params1': value,
            'params2': value2
        }
    }
    axios.post(url,formData,config)`

Hi @Sreekhar,
Did you solve the problem ? I didn't find the solution can someone help me ,Please.
Also, Thank You on advance

Hello,

I have been trying to post multiformdata(it is an Eztext SMS api)
using axios with node.js.

It works well for following code,
return new Promise(function(resolve, reject) {

        var request = require("request");
        var options = {
            method: 'POST',
            url: 'https://app.eztexting.com/sending/messages',
            qs: {format: 'json'},
            formData:
                {
                    User: '**',
                    Password: '**',
                    'PhoneNumbers[0]': '8572222***',
                    Message: 'Appointment Reminder',
                    MessageTypeID: '1'
                }
        };
        request(options, function (error, response, body) {
            if (error) {
                console.log(error);
                reject(error);
            }
            else {
                console.log(response);
                resolve(response);
            }

            // console.log(body);
        });

But it doesn't work with axios as SMS doesnt get sent but I get the status code as 200 for following request:-
var axios=require('axios');

         axios.post('https://app.eztexting.com/sending/messages', {
             qs: { format: 'json' },
             headers: {
                 'Content-Type': 'application/x-www-form-urlencoded'
             },
             formData:
                 { User: '****',
                     Password: '2sH****5',
                     'PhoneNumbers[0]':'85722******',
                     Message: 'Hello Yahska',
                     MessageTypeID: 1 }
         })
             .then(function (response) {
                 console.log(response);
             })
             .catch(function (error) {
                 console.log(error);
             });

why post request is a success with 'request' library and not with Axios?

Have u tried converting the data from JSON to FormData without setting any header?
Headers for the data (i.e. besides authentication headers) should be automatically handled

async function sendMessage(myJSONPayload){
  try{
    const data = convertJSON2FormData(myJSONPayload);

    const response = await axios.post('https://app.eztexting.com/sending/messages', {
  data
});
    console.log(response);
  } catch(ex){
    console error(err);
  }
}

sendMessage ({ User: '****',
                     Password: '2sH****5',
                     'PhoneNumbers[0]':'85722******',
                     Message: 'Hello Yahska',
                     MessageTypeID: 1 }
         });

For the conversion from JSON to FormData use something like in this answer

Remember that nested keys are tricky to handle. For instance, when sending data to our backend it works if we flatten them like this:

{a: {b: 2}} --> formData.append("a.b",2)

same problem here.

of course, @michaelscheurer! Setting the headers of a request is not enough: you must submit a FormData in order to make it work. It's a browser object that will be serialized with all the proper boundaries to work with the request... nor axios nor vanilla js will convert a JSON data to FormData for you. Axios will recognize that it's a FormData and also set the headers for you, so you don't really need to set them
Try following my previous answer hints...

@Iamuertepeluda
I tried following thing as per ur suggestion but no luck,,, same behavior as I get status 200 ok but SMS is not getting sent with following request
var axios=require('axios');

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

    const form = new FormData();

    //fo this jason I created a form
    // formData:
    // {
    //     User: '*****',
    //         Password
    // :
    //     '******',
    //         'PhoneNumbers[0]'
    // :
    //     '8****2763',
    //         Message
    // :
    //     'Appointment Reminder',
    //         MessageTypeID
    // :
    //     '1'
    // }

    form.append('User','****');
    form.append('Password','*****');
    form.append('PhoneNumbers[0]','*****');
    form.append('Message','Appointment Reminder');
    form.append('MessageTypeID','1');


         axios.post('https://app.eztexting.com/sending/messages', form,
    {
        qs: {format: 'json'},
        headers:
        {
                'content-type'
        :
            'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
        }
    }
)
             .then(function (response) {
                 console.log(response);
             })
             .catch(function (error) {
                 console.log(error);
             });

@Ruchi2729 are you using node.js or browser?

in a browser you don't need const FormData = require('form-data'); since FormData is native.

Furthermore try without setting headers and qs, or try

axios.request({
 url: "https://app.eztexting.com/sending/messages"
 type: "post",
 data: form //the instance of FormData of your stub
});

as I mentioned, it should set headers automatically in a browser

@Ruchi2729 i see you are using node, sorry.
I remember having used form-data with axios once but I don't recall if it actually worked.

But are you sure this is the correct way of sending SMS with eztexting? From their docs it seems different, like you should use an api key and their own node client...

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

Hey I am referring this document :- https://www.eztexting.com/developers/sms-api-documentation/rest#Sending
which document are you referring for API key and all?

@Ruchi2729
Sorry I confused with Nexmo, which is another SMS service and has its own client for node 😅

But anyway, according to the documentation you referred to, you can avoid FormData by setting format to json and let axios send a JSON payload (you can let it guess headers implicitly by the payload format)

https://app.eztexting.com/sending/messages?format=json

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

I have the same problem , I can see that I successfully send the file data with my dev tools but inside my contoller my $request->file('file') is empty
My component

submitForm() {
this.formData =new FormData();
this.formData.append('file',this.$refs.file.files[0]);
this.formData.append('analysis',this.analyticsForm.analysis);
this.formData.append('_method','PATCH');
axios.post('/analytics',
this.formData
,{headers: {'Content-Type': 'multipart/form-data'}}).then(response => this.isSubmittedRedirect(false,'/sources/'+this.source+'/description'+''))
.catch((error) => console.log(error))
},

I found that doing anything with FormData was a problem, since MVC doesn't seem to like getting anything that way, because you have to specify the Content-Type as multipart/form-data and it was throwing an exception when I'd check if (!Request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); }, as the Microsoft site says to do: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-2

Was better just to get my file into a base64 string:
https://stackoverflow.com/questions/37134433/convert-input-file-to-byte-array/49676679#49676679

This post might be more relevant to how to do that, as I used a DropZone in this example:
https://stackoverflow.com/questions/32556664/getting-byte-array-through-input-type-file/49660172#49660172

And I go more in detail on it, here: https://stackoverflow.com/questions/47574218/converting-from-blob-to-binary-to-save-it-to-mongodb/49660839#49660839

Then I could create a JSON object:

const myObj = {
   file = myBase64String,
   title = "myfileTitle.jpg"`
   type = "image/jpeg"`
}

Instead of using axios, I just used an XMLHttpRequest.

 const xhr = new XMLHttpRequest();

And open and set the header:

 xhr.open('POST', '/api/FileUpload/Post', true);
 xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8' );
 xhr.withCredentials = true;

I set the onreadystatechange to capture the response:

xhr.onreadystatechange = (response) =>
    if (xhr.readyState === 4 && xhr.status === 200) {
        console.log(response.target.responseText);
    }
}

and send:

 xhr.send(JSON.stringify(myObj));

If you use axios, it would probably be:

try {
    var axios = require('axios');
    const config = {
        headers: {
            'Content-Type': 'application/json;charset=UTF-8',
        }
    }
    await axios.post('https://example.com/api/upload/post', myObj, config)
        .then(function (response) {
             console.log(response);
         })
         .catch(function (error) {
             console.log(error);
         });
}
catch(e) { console.log(e); }

On the MVC side, you need a matching model:

public class MyModel {
    public string file { get; set; }
    public string title { get; set; }
    public string type { get; set; }
}

and then have that as a parameter in your Post call with a [FromBody] tag:

[System.Web.Http.HttpPost]
public virtual JsonResult<string> Post([FromBody]MyModel myModelObject)
{
    string strBase64FileString = myModelObject.file;
    string strTitle = myModelObject.title;
    string strFileType = myModelObject.type;

    return Json(JsonConvert.SerializeObject(new { file = myModelObject.file, title = myModelObject.title, myModelObject.type }));
}

You should get back what you sent. Note, if you implement this as a test, do so with a very small file, so you aren't waiting forever with the potential of locking up your system's browser/memory.

@navyjax2
I was doing like you said , it was working with small file but I need to send larges file ( > 250Mo), and yeah it was locking up my browser

Yeah, for that, you might want to break the file array into chunks of a manageable size and send in blocks, having a method on the other (server-side) end that can re-combine them, and giving it a parameter so it knows which chunk it is (1st, 2nd, 3rd, etc.) and how many total chunks to expect before it processes the file on the server-side. But I think, no matter what you do, with a file that size, you're going to have to wait for it to do its thing. Will have to be careful of memory management if you do it the chunk way, too, because you'd have to ensure you're clearing or re-using your variables each time and not re-instantiating new versions of the same variables each time you do a block. One of the few times a global variable is good - or just set to a model field each run.

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.

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) })
}

this worked:

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

I have the same problem

not working with golang

Just find a simple way in Vue, but I think it can be used in other situations.😀
Back-end: Express.js and express-fileupload package.

<template>
  <div>
    <input type="file"
           name=""
           id="file-upload"
           multiple
           @change="filesChange($event.target.files)">
    <button @click="handleSubmit">Send</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      formData: new FormData(),
    };
  },
  methods: {
    filesChange(fileList) {
      // First: append file to FormData
      Array.from(Array(fileList.length).keys()).map(x => {
        this.formData.append(fileList[x].name, fileList[x]);
      });
    },
    handleSubmit() {
      // Append Text
      this.formData.append('username', 'Jeremy');

      // Append Number: Will be string
      this.formData.append('number', 9527);

      // Append Array: Need to be converted to a string
      this.formData.append('arrData', JSON.stringify([1, 2, 3]));

      // Append Array: Need to be converted to a string
      this.formData.append(
        'objData',
        JSON.stringify({ name: 'Jeremy', age: 28 })
      );

      this.axios({
        method: 'post',
        url: `file/multi-users`,
        data: this.formData,
      }).then(res => {
        console.log(res);
      });
    },
  },
};
</script>

capture

Even we were facing the same issue. The content -type header was removed from react java script and then it worked fine. Earlier the boundary was not being set up when you explicitly set in the content-type

EDIT: After further reading about it appears Express was the issue on my end. Using a library like multer to read multipart forms was the key for my issue. Hopefully this could be of use to others

Same issue here. @nickuraltsev Would STRONGLY recommend reopening the issue.

I'm trying to post a file to my node server via axios using the following code:

let ff = new FileReader();
ff.onload = (ev) => {
      var result = ev.target.result;
      console.log(`result: ${result} of type ${typeof(result)}`);
      axios.post('/test', {
                 file: result
                 })
                 .then((response) => {
                         console.log(`Response: ${response}`)
                  })
                  .catch((err) => {
                        console.log(`Test error: ${err}`);
                   })
}

var sampleFile = //getting the file here
ff.readAsArrayBuffer(sampleFile);

Body of the request is completely empty server-side though

Tried sending the file directly, reading the file as an ArrayBuffer and reading the file as text (payload too large though) and all 3 didn't work.

Two years latter:
Same problem...

@demeter-macik thanks, adding boundary worked for me :smile:

    const form = new FormData();
    form.append('email', '[email protected]');
    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}`,
      },
    });

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

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)}
}

I'm wandering this library still require self-written workarounds for form data posts....

Any update?

I have similar error in NodeJS 10.11.0 and Axios 0.18.0 (see #1892). I've tried @arvi's fix but it don't work.

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})

beforeAll(function (done) {

          //parse form fields
          var parsefields = function(req,res){
            var form = new formidable.IncomingForm();
            form.parse(req, function (err, fields, files) {
              if (err) res.status(404).json(err)
              else res.status(200).json(fields);
            });  
          }

          router.route('parsefields').post(parsefields)

          //start server
          s = express()
          s.use('/',router)
          s.listen(4000,(err)=>{done(err)})
          done()
        });

        it('should parse and return form fields', function (done) {

          const fd = new FormData()
          fd.append('key','value')

          axios({
            method: 'POST',
            url: 'http://localhost:4000/parsefields',
            data: fd,
            headers : fd.getHeaders(),
          }).then(function (res) {
            expect(res).to.exist
            expect(res.body.key).to.equals('value')
          }).catch(err => {
            expect(err).not.to.exist
          })
          done()

        });
});

I'm having the same issue. Receiving a 404 with no error. Using formidable for form parser, express and axios.

I don't know if this helps anyone, but I was seeing this issue only on Safari and fixed it by using formdata-polyfill. Safari should be supporting FormData.append() natively but maybe the implementation is slightly different?

EDIT: I was wrong: I was using a URL created from a Blob. Once I started using the correct blob all worked like a charm!

I have the same problem with Blob while I can upload File. Converting from Blob to File is simple but I'd like to know if this is a bug or I misinterpreted the syntax:

``js upload () { let data = new FormData() data.append('file', this.croppedFile) data.append('blob', this.croppedBlob, 'blob.jpeg') axios.post('/api/fp/process/', data, { headers: { 'Accept':text/plain`,
},
})

croppedFile is derived from croppedBlob with this simple code:
   `   return new File([this.cropImg], this.file.name, { type: this.file.type })`

Firefox dev tools show:

------WebKitFormBoundarytmInU7WtcHvmgYbc
Content-Disposition: form-data; name="blob"

------WebKitFormBoundarytmInU7WtcHvmgYbc
Content-Disposition: form-data; name="file"; filename="dscn2950.jpg"
Content-Type: image/jpeg

blob:http://localhost:8080/9a6446d1-1ca2-4fd3-a6c8-8b36d863c146
------WebKitFormBoundarytmInU7WtcHvmgYbc--

```
According to mozilla formData.append documentation it seems I could use Blob objects.

What got me stuck was that my server was not handling files properly, using https://www.npmjs.com/package/multer fixed it

it's useful for me! Thanks!

Nothing here worked for me because my code was perfectly good.
The real issue was with the file I was dragging from windows search results - Chrome couldn't find the real location and it broke the entire FormData parsing. Navigating to the file and dragging it solved the issue.

Hi all,
Please help me.

POST https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart HTTP/1.1
Authorization: Bearer [YOUR_AUTH_TOKEN]
Content-Type: multipart/related; boundary=foo_bar_baz
Content-Length: [NUMBER_OF_BYTES_IN_ENTIRE_REQUEST_BODY]

--foo_bar_baz
Content-Type: application/json; charset=UTF-8

{
"name": "myObject"
}

--foo_bar_baz
Content-Type: image/jpeg

[JPEG_DATA]
--foo_bar_baz--

axios does not support multipart/related request type

For me it was (I guess) gulp. Because I was getting the error with minified files on my server. I deleted manually everything from the dist folder, left the content type as undefined and everythingg works as expected.
So you will have sth like:

formdata.append("selectPaymentType", $scope.extraFields.selectPaymentType);
formdata.append("pickupMethod", $scope.extraFields.selectPickupType);
let request = {
method: 'POST',
url: baseURL + 'orders',
data: formdata,
headers: {
'Content-Type': undefined,
'x-access-token': $scope.userToken
}
};
$http(request)
.success(function (d) { })
.error(function () { });

PS: This is excerpt ... I also attach files and alot more fields...

SERVER:

var form = new multiparty.Form({uploadDir : './uploads/orders/'});

form.parse(req, function(err, fields, files) {
//YOUR CODE HERE
})

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,

}

}
```

For anyone , this worked for me.
If are using input file, you have to use MULTER in your router.post('/') like a middleware, before getting the other input fields.

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: {}
});

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

Spent 2 days trying to get this to work with axios in nodejs. Spent 30 seconds to actually get it working with request-promise in nodejs.

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() })

@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.

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)
  }

You can do it in this way :
handleSubmit = (e: any) => {
e.preventDefault();
const data = new FormData();
data.append('product_csv', this.state.csvfile);
let accessToken = localStorage.getItem('access_token');
axios
.post('/upload', data,
{ headers:
{ 'Content-Type': 'multipart/form-data', Authorization: accessToken }
})
.then(res => {
console.log('res', res);
});
};

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

I'm using react-native. And I ended up this issue by using rn-fetch-blob. Too bad :(

I have the same issue, it just doesn't work with simple FormData without any file and .getHeaders() doesn't help. Moved to "got" lib that just works. Mentioned it here also https://github.com/form-data/form-data/issues/458 (I'm using Node v12)

2020 ES6 way of doing

Having the form in html I binded in data like so:

DATA:

form: {
   name: 'Joan Cap de porc',
   email: '[email protected]',
   phone: 2323,
   query: 'cap d\ou'
   file: null,
   legal: false
},

onSubmit:

async submitForm() {
  const formData = new FormData()
  Object.keys(this.form).forEach((key) => {
    formData.append(key, this.form[key])
  })

  try {
    await this.$axios.post('/ajax/contact/contact-us', formData)
    this.$emit('formSent')
  } catch (err) {
    this.errors.push('form_error')
  }
}

See: https://github.com/axios/axios/issues/789#issuecomment-508114703

On the receiving end, if you're using Express, you need multer. body-parser does not handle parsing multipart requests.

@DespertaWeb It doesn't work when there is no files.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Baoyx007 picture Baoyx007  ·  3Comments

jdpagley picture jdpagley  ·  3Comments

Adman picture Adman  ·  3Comments

ghprod picture ghprod  ·  3Comments

ghost picture ghost  ·  3Comments