Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way to send multipart/form-data using `fetch` or `request`

This is the structure of the data I want to send to the server:

{
   attachment: [File],
   foo: String,
   bar: String
}

As you can see, I am trying to send an array of files along with some other data. For storing all this data, I used FormData() constructor provided in the JavaScript official API. I am populating the formData like this:

for (let i = 0; i < this.state.files.length; i++) {
    let f = this.state.files[i];
    this.formData.append('attachment', f, f.name);
}
this.formData.append('foo', this.state.foo);
this.formData.append('bar', this.state.bar);

Sidenote: using React, react-dropzone for file upload. I am now trying to submit this data to the server. I first tried using the Fetch API like so:

fetch(url, {
    method: method,
    body: data,
    headers: {
      ...authHeader(authToken)
    }
}

Without too much success. Method is POST. authHeader(authToken) just generates Authorization: Bearer .... Problem was I think that the headers that get specified get overridden by my authentication header.

So I tried using request and request-promise-native. I did something like:

rp({
    url,
    method,
    headers: {
      ...authHeader(authToken)
    },
    formData: data
});

With similar results. What is the proper way to send this kind of data with Authorization Header and an array of Files from FormData?

like image 766
Dragos Strugar Avatar asked Oct 28 '25 18:10

Dragos Strugar


2 Answers

This are the options available in the fetch object

fetch(url, {
            method: "POST", // *GET, POST, PUT, DELETE, etc.
            mode: "cors", // no-cors, cors, *same-origin
            cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
            credentials: "same-origin", // include, *same-origin, omit
            headers: {
                "Content-Type": "application/json",
                // "Content-Type": "application/x-www-form-urlencoded",
            },
            redirect: "follow", // manual, *follow, error
            referrer: "no-referrer", // no-referrer, *client
            body: JSON.stringify(data), // body data type must match "Content-Type" header
        })

If you need to send some custom header to the server just write it like this:

headers: {
           "My-Custom-Header": "Custom-Header-Value",
         }

And because you want to send a multipart-form data you need to just add the data to the body of the request like this:

body: formData 

If you have your fields inside a form tag you could set your form data like this:

var formData = new FormData(document.querySelector("form"));

If you are using http authentication there are different authentication schemes, for reference use this link https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication

If your are using basic authorization then you should use something like this:

headers: {
           'Authorization': 'Basic '+btoa('username:password')
         }
like image 167
revobtz Avatar answered Oct 30 '25 07:10

revobtz


For future reference, I managed to send the data with the following configuration:

fetch(url, {
    method: method,
    body: data,
    headers: {
        'Accept': 'application/json',
        ...authHeader(authToken)
    }
})

That is, passing through the Accept header seems to have fixed the issue. Please also note that the Content-Type header is not set, allowing browser to set it by itself.

like image 29
Dragos Strugar Avatar answered Oct 30 '25 09:10

Dragos Strugar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!