35
votes

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.

6
Can you post the response as a sample?ShellNinja
Hey Amy are you trying to convert it to JSON ? Can you show full code ? And also response you getting from API ?Ulrich Dohou
“I thought that responseType: 'text' would be enough to make Angular expect a non JSON response.” - it would, if you specified it in the right place to begin with … this is not one of the HTTP headers!CBroe
Angular 7 HttpClient - If you came here from a Google Search this linked question and comment may be relevant to you if you are trying to get a string and NOT have the automatic JSON parse assumption. stackoverflow.com/a/57084925/2080879Sql Surfer

6 Answers

41
votes

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.

16
votes

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

7
votes

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))
2
votes

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'})
1
votes

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;
1
votes

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>>