Angular 6 Get response headers with httpclient issue
Asked Answered
C

1

14

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.

Comestible answered 21/6, 2018 at 12:32 Comment(2)
what is your problem? where do you try to get response status and it fails?Oldenburg
it doesn't fail as such I'm just trying to find the correct way to get to the ReturnStatus line in the response header.Comestible
O
27

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

Oldenburg answered 21/6, 2018 at 13:30 Comment(7)
Hi. Thanks for this. Unfortunately it looks like there maybe something else required also as this is a custom header? github.com/angular/angular/issues/5237 details adding "Access-Control-Expose-Headers" to the API...Comestible
let me know if you are not using spring, if I can I should help you to solve your backend troubles :)Oldenburg
Very much appreciate the offer of help for this issue. For the moment we've coded around it by returning an XML response and parsing that insteadComestible
key thing inside config - observe: "response" as 'body'. pipe tap is redundantSpies
If anyone is using CORS and ASP.NET on the server, you have to explicitly expose the header value with the exposedHeaders parameter when you configuring CORS.Priebe
adding , {observe: 'response'} actually solved my issue.. thanks a lot!!!Was so frustrated with this error.Yeaton
Also sometimes you want to change in node code in app.js put this.app.use(cors({ exposedHeaders: ['Content-Length', 'token'], })); Ref . truetocode.com/…Asp

© 2022 - 2024 — McMap. All rights reserved.