James
James

Reputation: 5777

fetch - Missing boundary in multipart/form-data POST

I want to send a new FormData() as the body of a POST request using the fetch api

The operation looks something like this:

var formData = new FormData()
formData.append('myfile', file, 'someFileName.csv')

fetch('https://api.myapp.com', 
  {
    method: 'POST',
    headers: {
      "Content-Type": "multipart/form-data"
    },
    body: formData
  }
)

The problem here is that the boundary, something like

boundary=----WebKitFormBoundaryyEmKNDsBKjB7QEqu

never makes it into the Content-Type: header

It should look like this:

Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryyEmKNDsBKjB7QEqu

When you try the "same" operation with a new XMLHttpRequest(), like so:

var request = new XMLHttpRequest()
request.open("POST", "https://api.mything.com")
request.withCredentials = true
request.send(formData)

the headers are correctly set

Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryyEmKNDsBKjB7QEqu

So my questions are:

  1. how do I make fetch behave exactly like XMLHttpRequest in this situation?
  2. if this is not possible, why?

Thanks everybody! This community is more or less the reason I have professional success.

Upvotes: 144

Views: 208894

Answers (8)

Pencilcheck
Pencilcheck

Reputation: 2932

I just use axios and it fixed without any special parameters. the node fetch really sucks

Upvotes: 0

Azamat Abdullin
Azamat Abdullin

Reputation: 201

According to FormData documentation, you shoudn't manually set the Content-Type header so browser itself will set it correctly:

Warning: When using FormData to submit POST requests using XMLHttpRequest or the Fetch_API with the multipart/form-data Content-Type (e.g. when uploading Files and Blobs to the server), do not explicitly set the Content-Type header on the request. Doing so will prevent the browser from being able to set the Content-Type header with the boundary expression it will use to delimit form fields in the request body.

So if your code (or library/middleware/etc) manually set the Content-Type, you have two ways to fix it:

  1. rewrite your code (or whatever you use) to don't set Content-Type by default
  2. set Content-Type to undefined or remove it from headers to let your browser do it's work

Upvotes: 19

Andrew Faulkner
Andrew Faulkner

Reputation: 3940

I had the same issue, and was able to fix it by excluding the Content-Type property, allowing the browser to detect and set the boundary and content type automatically.

Your code becomes:

var formData = new FormData()
formData.append('myfile', file, 'someFileName.csv')

fetch('https://api.myapp.com',
  {
    method: 'POST',
    body: formData
  }
)

Upvotes: 31

ravichandra vydhya
ravichandra vydhya

Reputation: 969

I removed "Content-Type" and added 'Accept' to http headers and it worked for me. Here are the headers I used,

'headers': new HttpHeaders({
        // 'Content-Type': undefined,
        'Accept': '*/*',
        'Authorization': 
        "Bearer "+(JSON.parse(sessionStorage.getItem('token')).token),
        'Access-Control-Allow-Origin': this.apiURL,
        'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, PATCH, DELETE',
        'Access-Control-Allow-Headers': 'origin,X-Requested-With,content-type,accept',
        'Access-Control-Allow-Credentials': 'true' 

      })

Upvotes: 22

Nver Abgaryan
Nver Abgaryan

Reputation: 621

Add headers:{content-type: undefined} browser will generate a boundary for you that is for uploading a file part-and-part with streaming if you are adding 'multiple/form-data' it means you should create streaming and upload your file part-and-part

So it is okay to add request.headers = {content-type: undefined}

Upvotes: 6

moonreader
moonreader

Reputation: 169

fetch(url,options)
  1. If you set a string as options.body, you have to set the Content-Type in request header ,or it will be text/plain by default.
  2. If options.body is specific object like let a = new FormData() or let b = new URLSearchParams(), you don't have to set the Content-Type by hand.It will be added automaticlly.

    • for a ,it will be something like

    multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

    as you see, the boundary is automaticlly added.

    • for b, it is application/x-www-form-urlencoded;

Upvotes: 15

James
James

Reputation: 5777

The solution to the problem is to explicitly set Content-Type to undefined so that your browser or whatever client you're using can set it and add that boundary value in there for you. Disappointing but true.

Upvotes: 258

Diego Troitiño
Diego Troitiño

Reputation: 321

I'm using the aurelia-api (an wrapper to aurelia-fetch-client). In this case the Content-Type default is 'application/json'. So I set the Content-Type to undefined and it worked like a charm.

Upvotes: 4

Related Questions