Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP Module using wrong Content-Type for multipart/form-data #37597

Closed
endigo9740 opened this issue Jun 15, 2020 · 14 comments
Closed

HTTP Module using wrong Content-Type for multipart/form-data #37597

endigo9740 opened this issue Jun 15, 2020 · 14 comments
Labels
area: common/http P4 A relatively minor issue that is not relevant to core functions
Milestone

Comments

@endigo9740
Copy link

🐞 bug report

Affected Package

The issue is is affecting package @angular/common/http

Is this a regression?

Not sure, only tested on Angular version 9.1.7

Description

Currently trying to upload a large file from Angular v9.1.7 to a Django API. I've been receiving the following error:

Multipart form parse error - Invalid boundary in multipart: None

Chrome's dev tools request header shows:
Content-Type: multipart/form-data

But should resemble the following:
Content-Type: multipart/form-data;boundary=----WebKitFormBoundaryyrV7KO0BoCBuDbTL

See the full discussion for this issue here:
JakeChampion/fetch#505
(@dgraham's response)

🔬 Minimal Reproduction

Here's a minimal sample of what's being used in Angular:

// Angular HTTP Module - POST method
const options: HttpOptions = {
    headers: new HttpHeaders({
        'Content-Type': 'multipart/form-data',
        'Authorization': `Bearer ${token}`
    })
}
this.http.post<any>(url, body, options).subscribe(res => {})

Here's my work around using the Github link provided in the description above:

// Native Javascript Fetch Method
fetch(url, {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${token}` },
    body: body,
});

Note that Fetch does not append a default content-type like the HTTP module. This means there is no satisfactory work around without using Fetch in place of the HTTP module currently.

🔥 Exception or Error

Multipart form parse error - Invalid boundary in multipart: None

Chrome's dev tools request header shows:
Content-Type: multipart/form-data

But should resemble the following:
Content-Type: multipart/form-data;boundary=----WebKitFormBoundaryyrV7KO0BoCBuDbTL

🌍 Your Environment

Angular Version:



     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 9.1.6
Node: 12.14.1
OS: darwin x64

Angular: 9.1.7
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.901.6
@angular-devkit/build-angular     0.901.6
@angular-devkit/build-optimizer   0.901.6
@angular-devkit/build-webpack     0.901.6
@angular-devkit/core              9.1.6
@angular-devkit/schematics        9.1.6
@angular/cdk                      9.2.4
@angular/cli                      9.1.6
@angular/material                 9.2.4
@ngtools/webpack                  9.1.6
@schematics/angular               9.1.6
@schematics/update                0.901.6
rxjs                              6.5.5
typescript                        3.8.3
webpack                           4.42.0

Tested in Chrome version 83.0.4103.97

@bwqr
Copy link

bwqr commented Sep 8, 2020

I think, I also hit this bug. In my case, my "Content-Type": "multipart/formdata" header is overwritten by "Content-Type": "application/json". This causes backend to parse requests incorrectly. A simple example is:

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

 let headers = new HttpHeaders();
    headers = headers.append('Content-Type', 'multipart/form-data');
    headers = headers.append('enctype', 'multipart/form-data');

this.http
     .post(url, formData, {headers}).subscribe(_ => {});

Whatever I have tried, like not setting any header, in network tab of dev tools shows me the "Content-Type": "application/json" value.

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 10.0.7
Node: 14.8.0
OS: linux x64

Angular: 10.0.11
... animations, common, compiler, compiler-cli, core, forms
... language-service, localize, platform-browser
... platform-browser-dynamic, router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.1000.7
@angular-devkit/build-angular     0.1000.7
@angular-devkit/build-optimizer   0.1000.7
@angular-devkit/build-webpack     0.1000.7
@angular-devkit/core              10.0.7
@angular-devkit/schematics        10.0.7
@angular/cdk                      10.1.3
@angular/cli                      10.0.7
@angular/material                 10.1.3
@ngtools/webpack                  10.0.7
@schematics/angular               10.0.7
@schematics/update                0.1000.7
rxjs                              6.6.2
typescript                        3.9.7
webpack                           4.43.0

@JoostK
Copy link
Member

JoostK commented Sep 8, 2020

@bwqr Did you mean to do

this.http
     .post(url, formData, { headers }).subscribe(_ => {});

@bwqr
Copy link

bwqr commented Sep 8, 2020

@JoostK exactly, my miss

@bwqr
Copy link

bwqr commented Sep 8, 2020

I am indeedly sorry for misinformation. The cause of my problem is the http interceptor, which is setup by myself. I was overriding the content-type in interceptor. After fixing the interceptor, my request's headers are sent as expected.

@bwqr
Copy link

bwqr commented Sep 8, 2020

I think, this bug report has nothing to do with angular/common/http. While sending a formData, explicitly setting Content-Type on the request is wrong, instead, enctype header field should be set to multipart/form-data. Then browsers will automatically set

"Content-Type": "multipart/form-data; boundary {}"

with correct values.

@atscott
Copy link
Contributor

atscott commented Oct 21, 2020

Duplicate of #36274.

@atscott atscott closed this as completed Oct 21, 2020
@atscott
Copy link
Contributor

atscott commented Oct 21, 2020

My mistake, re-opening. This is in reference to the request headers, not the response as #36274.

@atscott atscott reopened this Oct 21, 2020
@jelbourn
Copy link
Member

jelbourn commented Nov 4, 2020

@bwqr @atscott to make sure I understand- is this bug that something in Angular is setting a wrong http request header?

@jelbourn jelbourn added the P4 A relatively minor issue that is not relevant to core functions label Nov 4, 2020
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Nov 4, 2020
@mpeguero
Copy link

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

 let headers = new HttpHeaders();
    headers = headers.append('Content-Type', 'multipart/form-data');
    headers = headers.append('enctype', 'multipart/form-data');

this.http
     .post(url, formData, {headers}).subscribe(_ => {});

//SOLUTION: request headers are inmutable, append is only for custom headers

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

 let headers = new HttpHeaders({ 'Content-Type': 'multipart/form-data',
                                                     'enctype': 'multipart/form-data'});

this.http
     .post(url, formData, {headers}).subscribe(_ => {});

@kumaresan-subramani
Copy link

any update on this issue...!

@endigo9740
Copy link
Author

Yes, the original issue was resolved for me since at least version 12. Possibly sooner. Just update and try as per the desired method using the HTTP method in my original post and all should be well.

@rajkumar30598
Copy link

@endigo9740 , this is something I am trying but still the same issue in angular - 12.1.4

  uploadCSV(listName, fileToUpload): Observable<any> {
    let url =
      invoice_adjustment.url +
      `mylist/uploadCsv?userId=${this.getUserID()}&listName=${listName}`;
    const uploadedFile = new FormData();
    uploadedFile.append('file', fileToUpload, fileToUpload.name);

    let headers = new HttpHeaders({
      enctype: 'multipart/form-data',
      Accept: 'application/json',
    });
    let options = {
      headers: headers,
    };
    return this.http.post(url, uploadedFile, options);
  }

any sugegstions...!

@YogiDhingani27
Copy link

YogiDhingani27 commented Feb 1, 2022

There is no need to pass header in post request, browser automatically passed content type as multipart/form-data if you're passing FormData object:

addImage(file: FormData) {
    return this.http.post(this.GALLERY_URL, file, { responseType: 'text' }).pipe(
      map(response => { return response; })
    )
  }

In my case i written { responseType: 'text' } because my api response is text, so don't confuse with this line.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Mar 4, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: common/http P4 A relatively minor issue that is not relevant to core functions
Projects
None yet
Development

No branches or pull requests

10 participants