-
Notifications
You must be signed in to change notification settings - Fork 26.5k
Description
🐞 bug report
Affected Package
The issue is caused by package @angular/common/httpIs this a regression?
No.Description
TLDR:
A boolean as body is seen as text/plain
where is should be seen as application/json
, since it is valid JSON, like numbers. See:
https://jsonlint.com/
https://www.json.org/json-en.html
Detailed description:
The post()
method of HttpClient
(and other request methods) accept a body method argument of type any
. When the HTTP request is about to execute, HttpClient
will determine the content type of body
, so that it can set the Content-Type
header to for example application/json
or text/plain
.
When an object is used as body
, HttpClient will send it as application/json
as expected.
When a plain number is used as body
(e.g. 123
, without quotes), HttpClient will also send it as application/json
, because even a plain number (without curly braces and without quotes) is valid JSON.
When a TypeScript string is used as body
argument (e.g. "abc"
), HttpClient will send it as text/plain
because it will be send without quotes in the HTTP request body, and thus isn't valid JSON. So it will use text/plain
as expected.
But when boolean is used, this behavior is different. When a plain boolean (e.g. true
) is used as body
argument, HttpClient will send it as text/plain
even though a simple plain boolean is valid JSON.
The code where this problems is caused is:
angular/packages/common/http/src/request.ts
Line 295 in 2686219
if (typeof this.body === 'object' || typeof this.body === 'number' || |
// Arrays, objects, and numbers will be encoded as JSON.
if (typeof this.body === 'object' || typeof this.body === 'number' || Array.isArray(this.body)) {
return 'application/json';
}
Plain objects, numbers, booleans and arrays values are all valid JSON code. Whereas a plain string without quotes it not valid JSON.
So plain objects, numbers, booleans and arrays values should be send as application/json
and strings as text/plain
. But in HttpClient this behavior unexpectedly differs for booleans.
🔬 Minimal Reproduction
https://stackblitz.com/edit/angular-ivy-umexba?file=src/app/app.component.ts
import { Component, VERSION } from '@angular/core';
import {HttpClient} from '@angular/common/http';
@Component({
selector: 'my-app',
template: `
<button (click)="sendObject()">Send object</button>
<button (click)="sendNumber()">Send number</button>
<button (click)="sendBoolean()">Send boolean</button>
<button (click)="sendString()">Send string</button>
`
})
export class AppComponent {
constructor(private httpClient: HttpClient) {}
sendObject() {
// 'application/json'
this.httpClient.post<any>("http://localhost", {x: 1}).subscribe();
}
sendNumber() {
// 'application/json'
this.httpClient.post<any>("http://localhost", 123).subscribe();
}
sendBoolean() {
// `text/plain`, but should be 'application/json'
this.httpClient.post<any>("http://localhost", true).subscribe();
}
sendString() {
// `text/plain`
this.httpClient.post<any>("http://localhost", "abc").subscribe();
}
}
🌍 Your Environment
Angular Version:
10.1.2