-
Notifications
You must be signed in to change notification settings - Fork 27.1k
HttpClient - incorrect ContentType for boolean #38924
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
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