Angular 4.3.3 HttpClient : How get value from the header of a response?

Viewed 130901

( Editor: VS Code; Typescript: 2.2.1 )

The purpose is to get the headers of the response of the request

Assume a POST request with HttpClient in a Service

import {
    Injectable
} from "@angular/core";

import {
    HttpClient,
    HttpHeaders,
} from "@angular/common/http";

@Injectable()
export class MyHttpClientService {
    const url = 'url';

    const body = {
        body: 'the body'
    };

    const headers = 'headers made with HttpHeaders';

    const options = {
        headers: headers,
        observe: "response", // to display the full response
        responseType: "json"
    };

    return this.http.post(sessionUrl, body, options)
        .subscribe(response => {
            console.log(response);
            return response;
        }, err => {
            throw err;
        });
}

HttpClient Angular Documentation

The first problem is that I have a Typescript error :

'Argument of type '{ 
    headers: HttpHeaders; 
    observe: string; 
    responseType: string;
}' is not assignable to parameter of type'{ 
    headers?: HttpHeaders;
    observe?: "body";
    params?: HttpParams; reportProgress?: boolean;
    respons...'.

Types of property 'observe' are incompatible.
Type 'string' is not assignable to type '"body"'.'
at: '51,49' source: 'ts'

Indeed, when I go to the ref of post() method, I point on this prototype (I Use VS code)

post(url: string, body: any | null, options: {
        headers?: HttpHeaders;
        observe?: 'body';
        params?: HttpParams;
        reportProgress?: boolean;
        responseType: 'arraybuffer';
        withCredentials?: boolean;
    }): Observable<ArrayBuffer>;

But I want this overloaded method :

post(url: string, body: any | null, options: {
    headers?: HttpHeaders;
    observe: 'response';
    params?: HttpParams;
    reportProgress?: boolean;
    responseType?: 'json';
    withCredentials?: boolean;
}): Observable<HttpResponse<Object>>;

So, I tried to fix this error with this structure :

  const options = {
            headers: headers,
            "observe?": "response",
            "responseType?": "json",
        };

And It compiles! But I just get the body request as in json format.

Futhermore, why I have to put a ? symbol at the end of some name of fields ? As I saw on Typescript site, this symbol should just tell to the user that it is optional ?

I also tried to use all the fields, without and with ? marks

EDIT

I tried the solutions proposed by Angular 4 get headers from API response. For the map solution:

this.http.post(url).map(resp => console.log(resp));

Typescript compiler tells that map does not exists because it is not a part of Observable

I also tried this

import { Response } from "@angular/http";

this.http.post(url).post((resp: Response) => resp)

It compiles, but I get a unsupported Media Type response. These solutions should work for "Http" but it does not on "HttpClient".

EDIT 2

I get also a unsupported media type with the @Supamiu solution, so it would be an error on my headers. So the second solution from above (with Response type) should works too. But personnaly, I don't think it is a good way to mix "Http" with "HttpClient" so I will keep the solution of Supamiu

7 Answers

If you use the solution from the top answer and you don't have access to .keys() or .get() on response.headers, make sure that you're using fetch rather than xhr.

Fetch requests are the default, but Angular will use xhr if xhr-only headers are present (e.x. x-www-form-urlencoded).

If you are trying to access any custom response headers, then you have to specify those headers with another header called Access-Control-Expose-Headers.

Some times even with the above solution you can't retrieve custom headers if it is CORS request. In that case you need to whitelist desired headers in server side.

For Example: Access-Control-Expose-Headers: X-Total-Count

The below method worked perfectly for me (currently Angular 10). It also avoids setting some arbitary filename, instead it gets the filename from the content-disposition header.

this._httpClient.get("api/FileDownload/GetFile", { responseType: 'blob' as 'json', observe: 'response' }).subscribe(response =>  { 
    /* Get filename from Content-Disposition header */
    var filename = "";
    var disposition = response.headers.get('Content-Disposition');
    if (disposition && disposition.indexOf('attachment') !== -1) {
        var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
        var matches = filenameRegex.exec(disposition);
        if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
    }
    // This does the trick
    var a = document.createElement('a');
    a.href = window.URL.createObjectURL(response.body);
    a.download = filename;
    a.dispatchEvent(new MouseEvent('click'));
})

As other developers said, for getting headers and body together you should define the type of observer yield in this way:

http.post("url", body, {headers: headers, observe: "response" as "body"})

Then you can access to body and headers in pip or a subscribe area:

http.post("url", body, {headers: headers, observe: "response" as "body"})
.pip(
  tap(res => {
   // res.headers
   // res.body
  })
)
.subscribe(res => {
   // res.headers
   // res.body
})
Related