Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to POST with multipart/form-data header and FormData using fetch

This is a CURL example which works fine:

curl -X POST \
  <url> \
  -H 'authorization: Bearer <token>' \
  -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
  -F [email protected] \
  -F userId=<userId>

I'm trying to reproduce this request using isomorphic-fetch.

I've tried the following code:

const formData = new FormData();
formData.append('file', file);
formData.append('userId', userId);

return fetch(`<url>`, {      
  method: 'POST',
  headers: {
    'Content-Length': file.length
    'Authorization: Bearer <authorization token>',
    'Content-Type': 'multipart/form-data'
  },
  body: formData
})`

I use fs.readFileSync in order to generate the file passed to FormData.

The previous example returns a 401 HTTP status code (unauthorized) with an error message saying that the userId embedded in the token (sent via header) does not match the userId passed from formData.

So my suspicion is that the FormData that arrives to the REST API is not adequately formed.

The problem may be related with the Content-Length header, but I didn't find a better way to calculate it (if I don't use the Content-Length header I get a 411 HTTP status code Content-Length header missing).

Could be the case that this is failing because of an incorrect value in the Content-Length header?

Any other suggestions on why this is failing or how to better debug it?

If further info is needed to clarify this problem, please just ask.

UPDATE

I've tried the form-data module in order to get the right Content-Length value using the method formData.getLengthSync()

However the problem remains the same (401 error HTTP status code response).

like image 775
rfc1484 Avatar asked Apr 19 '17 15:04

rfc1484


People also ask

How do you send form data in fetch react?

The method attribute specifies how to send form-data (the form-data is sent to the page specified in the action attribute). The form-data can be sent as URL variables (with method=”get” ) or as HTTP post transaction (with method=”post” ). Notes on GET: Appends form-data into the URL in name/value pairs.

How do I upload a multipart form data?

Multipart form data: The ENCTYPE attribute of <form> tag specifies the method of encoding for the form data. It is one of the two ways of encoding the HTML form. It is specifically used when file uploading is required in HTML form. It sends the form data to server in multiple parts because of large size of file.

Can fetch API be used for post?

Fetch API comes with a fetch () method that allows you to fetch data from all sorts of different places and work with the data fetched. It allows you to make an HTTP request, i.e., either a GET request (for getting data) or POST request (for posting data).


2 Answers

If you open up your network inspector, run this code snippet, and submit the form you should see that the Content-Length is set correctly:

const foo = document.getElementById('foo')
foo.addEventListener('submit', (e) => {
  e.preventDefault()
  const formData = new FormData(foo)
  formData.append('userId', 123)
  fetch('//example.com', {
    method: 'POST',
    body: formData
  })
})
<form id="foo">
  <input id="file" type="file" name="file"/><br><br>
  <button type="submit">Submit</button>
</form>

like image 88
idbehold Avatar answered Oct 15 '22 14:10

idbehold


I hit my head against a similar wall, specifically using isomorphic-fetch on node to POST a multipart form. The key for me was finding .getHeaders(). Note that NPM description for form-data suggests that it'll "just work" without this, but it doesn't seem to, at least not in node (I think browsers inject header stuff?).

// image is a Buffer containing a PNG image
// auth is the authorization token

const form_data  = new FormData();
form_data.append("image", png, {
    filename: `image.png`,
    contentType: 'application/octet-stream',
    mimeType: 'application/octet-stream'
});

const headers = Object.assign({
    'Accept': 'application/json',
    'Authorization': auth,
}, form_data.getHeaders());

try {
    const image_res = await fetch(url, {
        method: 'POST',
        headers: headers,
        body: form_data
    });

    if (!image_res.ok) {
        const out = await image_res.json();
        console.dir(out);
        return;
    }
}
catch (e) {
    console.error(`Chart image generation exception: ${e}`);
}
like image 38
Iain Bryson Avatar answered Oct 15 '22 16:10

Iain Bryson