Content-type problem when sending json AND file in same FormData
See original GitHub issueBug Report
Hello.
Affected Package
The issue is caused by package @angular/common/http
(HttpClient
)
Is this a regression?
I have no idea. I never did anything similare before I post this issue there.
Description
I am sorry, I won’t be able to provide a Minimal Reproduction since it require a back-end as well (I use Spring Boot here) so the description will contain all the detail you’ll need.
– Short:
What I want: I’m trying to send a FormData that contains a JSON and a File (in the same FormData).
What I expect: The function on the back-end that is responsible of the API (a DTO, a Multipartfile) should be able to get the JSON + the file.
What I have: The DTO contains only null values, I correctly get the file.
Additional information: Why I’m posting here is because, using Postman, all works as expected.
– Long:
Here is an example of what I’m doing.
Front-End service function:
createToto(totoDTO: TotoDTO, file: File): Observable<void> {
const formData = new FormData();
formData.append('toto', JSON.stringify({ totoDTO }));
formData.append('file', file, file.name);
return this.http.post<void>(`${TotoService.URL}`, formData);
}
Back-End controller function:
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void createToto(@RequestPart("toto") TotoDTO totoDTO, @RequestPart("file") MultipartFile multipartFile, Principal loggedUser) throws IOException {
System.out.println(totoDTO);
System.out.println(multipartFile.getOriginalFilename());
//totoService.createToto(totoDTO, multipartFile, loggedUser.getName());
}
So when I send a request from the Front-End to the Back-End, the Back-End tell me that Content type 'application/octet-stream' not supported
:
2021-06-24 16:04:17.812 WARN 18820 --- [nio-8080-exec-5] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported]
The request header looks like this (it’s a content-type multipart):
------WebKitFormBoundary4WervCkSHzbAcd2L
Content-Disposition: form-data; name="toto"
{"toto":{"id":6,"unChamp":"coucou"}}
------WebKitFormBoundary4WervCkSHzbAcd2L
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
------WebKitFormBoundary4WervCkSHzbAcd2L--
I did some research and then found out that for the DTO it should be stored in a Blob like this:
...
formData.append(
'toto',
new Blob([JSON.stringify({ totoDTO })], {
type: 'application/json'
})
);
...
The request header looks like this, here the DTO have Content-Type: application/json
which should be fine:
------WebKitFormBoundaryocSMA44WAWzYVkwC
Content-Disposition: form-data; name="toto"; filename="blob"
Content-Type: application/json
{"toto":{"id":6,"unChamp":"coucou"}}
------WebKitFormBoundaryocSMA44WAWzYVkwC
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
------WebKitFormBoundaryocSMA44WAWzYVkwC--
Fine, the Back-End doesn’t cry anymore but the json received on the Back-End seems to be empty or isn’t in the good form:
TotoDTO(id=null, unChamp=null)
test.txt
So, why am I posting an issue here?
Because if I’m using Postman, all works as intended:
I get the proper DTO (nothing null) and the file.
I suspect something being wrong on the Angular side, either it’s my fault on not properly setting something or it’s a “bug”.
Maybe I’m not thinking properly and shouldn’t send a file with a json (DTO) ? I don’t want to use 2 differents request for that. Maybe It’s better to send a base64 file?
Your Environment
Angular Version:
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI: 11.2.11
Node: 14.16.1
OS: win32 x64
Angular: 11.2.12
... 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.1102.11
@angular-devkit/build-angular 0.1102.11
@angular-devkit/core 11.2.11
@angular-devkit/schematics 11.2.11
@angular/cdk 11.2.11
@angular/cli 11.2.11
@angular/material 11.2.11
@schematics/angular 11.2.11
@schematics/update 0.1102.11
rxjs 6.6.7
typescript 4.1.5
Issue Analytics
- State:
- Created 2 years ago
- Comments:5 (2 by maintainers)
Top GitHub Comments
You appear to be hitting specific Spring behavior where a request part with a
filename
in itsContent-Disposition
header is interpreted as a file:https://github.com/spring-projects/spring-framework/blob/ddbb7c1b5b003018ee4ebd483ca4a22dd60a53c7/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java#L98-L108
When making the request from Postman it’s likely not including the
filename="blob"
data, which avoids Spring from interpreting it as a file.I’m afraid there isn’t anything we can do from the Angular side of things, as handling of
FormData
is entirely up to the browser.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.