Angular 6 Get response headers with httpclient issue

Mark Beynon picture Mark Beynon · Jun 21, 2018 · Viewed 39k times · Source

I'm using the code below to try to extract a value (ReturnStatus) from the response headers;

Keep-Alive: timeout=5, max=100
ReturnStatus: OK,SO304545
Server: Apache/2.4.29 (Win32) OpenSSL/1.0.2m

The code;

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

import { Account } from './model/account';
import { HttpClient } from '@angular/common/http';
import { Observable, throwError } from "rxjs";
import { map, filter, catchError, mergeMap } from 'rxjs/operators';

 createOrder(url) : Observable<any> {

  return this._http.get(url, {withCredentials: true, observe: 'response'})
  .pipe(
    map((resp: any) => {
      console.log("response", resp);
      return resp;

    }), catchError( error => {
      console.log("createOrder error",error );
      alert("Create Order Service returned an error. See server log for mote details");
    return throwError("createOrder: " + error)

    })
  );
}

However my console.log just give;

HttpResponse {headers: HttpHeaders, status: 200, statusText: "OK", url: 
"http://localhost/cgi-bin/dug.cgi/wh?Page… 
plateLocation=C:%5Ctemp%5Corderimporttemplate.txt", ok: true, …}

I've looked on this site and others for the correct way to do this in Angular but to no avail? Could someone point me in the right direction please?

Many thanks,

Mark.

Answer

firegloves picture firegloves · Jun 21, 2018

You need to observe the entire response as described below:

 createOrder(url) : Observable<HttpResponse<Object>>{

    return this.http.get<HttpResponse<Object>>(this.url, {observe: 'response'}).pipe(
         tap(resp => console.log('response', resp))
    );
}

Now inside resp you can access headers An example

 createOrder(url) : Observable<HttpResponse<Object>>{

    return this.http.get<HttpResponse<Object>>(this.url, {observe: 'response'}).pipe(
         tap(resp => console.log('heaeder', resp.headers.get('ReturnStatus')))
    );
}

If you can't access your custom header as explained above it's because a small set of headers are exposed to javascript by default for security reasons. Probably if you open developer tools and you inspect your response headers you should see the desired one.

Who can choose which headers are exposed to javascript?

Exposed headers are choosen by the web application (so your webservices, or your backend. Obviously you web application could be written using many languages and/or using many framework.

Depending on what you are using you can achieve this goal by different ways.

To give you an idea of what you should do I can post my Spring solution. In class extending WebSecurityConfigurerAdapter you should add this two methods:

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
            // we don't need CSRF because our token is invulnerable
            .csrf().disable()
            .cors()
} 


@Bean
public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addExposedHeader("Authorization, x-xsrf-token, Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, " +
            "Content-Type, Access-Control-Request-Method, Custom-Filter-Header");
    config.addAllowedHeader("*");
    config.addAllowedMethod("OPTIONS");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("DELETE");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}

Note that I've disabled csrf because I'm using JWT. Note that you should refine CorsFilter rules.

As you can see I have added Custom-Filter-Header into this line

config.addExposedHeader("Authorization, x-xsrf-token, Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, " +
                "Content-Type, Access-Control-Request-Method, Custom-Filter-Header");

You can replace this Custom-Filter-Header with your ReturnStatus