'HTTPClient POST tries to parse a non-JSON response
I'm trying to make a request in Angular and I know that the HTTP response will not be in JSON but in text. However, Angular seems to be expecting a JSON response since the error is the following:
SyntaxError: Unexpected token < in JSON at position 0 at JSON.parse () at XMLHttpRequest.c
As well as
Http failure during parsing for http://localhost:9...
This is the post method:
return this.http.post(this.loginUrl, this.createLoginFormData(username, password), this.httpOptions)
.pipe(
tap( // Log the result or error
data => console.log(data);
error => console.log(error)
)
);
and the headers.
private httpOptions = {
headers: new HttpHeaders({
'Accept': 'text/html, application/xhtml+xml, */*',
'Content-Type': 'application/x-www-form-urlencoded',
responseType: 'text'
},
) };
I thought that responseType: 'text'
would be enough to make Angular expect a non JSON response.
Solution 1:[1]
You've put responseType: 'text'
in the wrong section of your httpOptions
- It should sit outside of headers
, like so:
private httpOptions = {
headers: new HttpHeaders({
'Accept': 'text/html, application/xhtml+xml, */*',
'Content-Type': 'application/x-www-form-urlencoded'
}),
responseType: 'text'
};
With what you had before, a request header of responseType
was being sent to the server, rather than simply having an instruction to Angular to actually treat the response as text.
Solution 2:[2]
This code finally worked for me to xhr download a pdf file (Angular 6 / Laravel 5.6).
The specialty for downloading a PDF file vs a text file was 'responseType': 'blob' as 'json'
showPdf(filename: String){
this.restService.downloadFile(
'protected/getpdf',
{'filename': filename}
)
}
//method from restService
public downloadFile(endpoint:String, postData:Object){
var restService = this
var HTTPOptions = {
headers: new HttpHeaders({
'Accept':'application/pdf'
}),
'responseType': 'blob' as 'json'
}
this.http.post(this.baseurl+endpoint,postData,HTTPOptions )
.subscribe(
res => {
console.log(res) //do something with the blob
},
error => {
console.error('download error:', error)
},
() => {
console.log('Completed file download.')
}
)
}
I found the Solution through Kirk Larkins Answer (thank you a lot!) and a long angular github issue thread https://github.com/angular/angular/issues/18586#issuecomment-323216764
Solution 3:[3]
If you just want to receive a plain text. You can set Http option without a header.
this.http.get("http://localhost:3000/login",{responseType: 'text'})
.subscribe((result)=>console.log(result))
Solution 4:[4]
By default, Angular sets the response type to JSON.
To override it, you can use headers and set the responseType
to 'text'
or a simple method would be like this
this.http.get(url, {responseType: 'text'})
Solution 5:[5]
Below given is the call from component which downloads the blob, compatible with IE and chrome:
this.subscribe(this.reportService.downloadReport(this.reportRequest, this.password), response => {
let blob = new Blob([response], { type: 'application/zip' });
let fileUrl = window.URL.createObjectURL(blob);
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, fileUrl.split(':')[1] + '.zip');
} else {
this.reportDownloadName = fileUrl;
window.open(fileUrl);
}
this.spinner = false;
this.changeDetectorRef.markForCheck();
},
error => {
this.spinner = false;
});
Below given is the service method which specifies the response type to be 'blob'
downloadReport(reportRequest: ReportRequest, password: string): Observable<any> {
let servicePath = `${basePath}/request/password/${password}`;
this.httpOptions.responseType = 'blob';
return this.endpointService.post(endpoint, servicePath, reportRequest, this.httpOptions);
}
Below is the code that makes httpClient call:
//Make the service call:
let obs = this.httpClient.request(method, url, options);
//Return the observable:
return obs;
Solution 6:[6]
I had the same problem after an angular update due http client was updated to parse the response as JSON, failing when the response doesn't contains a valid json (i.e a text or a raw html).
To avoid automatic json parsing, add the header "responseType" as a parameter in the get or post call:
this.http.get(template,{responseType:'text'})
.subscribe(result => {
// result contains the "treated as text content"
});
In general: If expect a Json result (like in a rest api):
HttpClient.get(url) // returns Observable Json formatted
If text or raw html is expected:
HttpClient.get(url, {responseType:'text'}) // returns a string Observable
If the return type is unexpected (You'll get the headers as well so you can parse your data properly):
HttpClient.get(url, {observe:response}) //returns Observable<HttpResponse <T>>
Solution 7:[7]
Using Angular 13:
For text responses:
var options = {
headers: new HttpHeaders({
'Accept':'text/plain'
}),
'responseType': 'text' as 'json'
}
this.http.post(url,null,options).subscribe(...
For binary file responses:
var options = {
headers: new HttpHeaders({
'Accept':'image/jpeg' //or 'Accept':'application/pdf' .. etc
}),
'responseType': 'blob' as 'json'
}
this.http.post<Blob>(url,null,options).subscribe(...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Kirk Larkin |
Solution 2 | |
Solution 3 | Joe |
Solution 4 | |
Solution 5 | Dilip Nannaware |
Solution 6 | Jorge Valvert |
Solution 7 |