114

I'm triggering a HTTP request and I'm getting a valid response from it. The response also has a header X-Token that I wish to read. I'm trying the below code to read the headers, however, I get null as a result

this.currentlyExecuting.request = this.http.request(reqParams.type, reqParams.url, {
    body: reqParams.body,
    responseType: 'json',
    observe: 'response'
}).subscribe(
    (_response: any) => {
        // Also tried _response.headers.init();
        const header = _response.headers.get('X-Token');
        console.log(header);
        onComplete(_response.body);
     },
    _error => {
        onComplete({
            code: -1,
            message: Constants.WEBSERVICE_INTERNET_NOT_CONNNECTED
        });
    }
);

The response of the API, when checked in Chrome inspect, shows the header is present.

enter image description here

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Sahil Khanna
  • 4,262
  • 8
  • 47
  • 72
  • 4
    have you expose the x-token from server side? using "access-control-expose-headers". because not all headers are allowed to be accessed from the client side, you need to expose them from the server side. – Hrishikesh Kale Jan 10 '18 at 09:30
  • 8
    If he has it in the console, then yes, he exposed it. –  Jan 10 '18 at 09:37
  • 2
    @HrishikeshKale: You are right. Access-Control-Expose-Headers worked. You may post this as an answer. – Sahil Khanna Jan 10 '18 at 09:48
  • i have posted this as an answer. happy coding :) – Hrishikesh Kale Jan 10 '18 at 10:01
  • 5
    trichetriche, I don't agree. I had a situation where I was adding the header on the server and could see it in the browser console, but the browser code couldn't see it. I had to explicitly mark it to be exposed (in my server code) to the browser because of CORS. – John Gilmer Dec 26 '18 at 07:43
  • see this: https://stackoverflow.com/questions/58601675/angular-how-to-get-headers-value-in-the-canactive-function/58602196#58602196 – Abolfazl Roshanzamir Oct 30 '19 at 06:23

9 Answers9

190

Have you exposed the X-Token from server side using access-control-expose-headers? because not all headers are allowed to be accessed from the client side, you need to expose them from the server side

Also in your frontend, you can use new HTTP module to get a full response using {observe: 'response'} like

http
  .get<any>('url', {observe: 'response'})
  .subscribe(resp => {
    console.log(resp.headers.get('X-Token'));
  });
Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Hrishikesh Kale
  • 6,140
  • 4
  • 18
  • 27
  • 3
    is it same for post method also... i am getting error "Request header field observe is not allowed by Access-Control-Allow-Headers in preflight response." – KoolKabin Mar 17 '18 at 13:24
  • Where can I read more about this? This fixed my problem but I'd like to know what's going on – Kai CriticallyAcclaimed Cooper Jun 28 '18 at 13:15
  • @KaiCriticallyAcclaimedCooper yes sure here is the link https://www.html5rocks.com/en/tutorials/cors/ also, there is Github issue https://github.com/angular/angular/issues/6583 – Hrishikesh Kale Jun 29 '18 at 05:02
  • I still have problem to read Headers , I found the answer , see this: https://stackoverflow.com/questions/58601675/angular-how-to-get-headers-value-in-the-canactive-function/58602196#58602196 – Abolfazl Roshanzamir Oct 30 '19 at 06:23
  • I could see the header in postman. Does it mean header is exposed or not? I am not getting that header when i use above code @HrishikeshKale – sreenivas Nov 26 '20 at 12:07
  • @sreenivas are you able to send header from your api? – Hrishikesh Kale Nov 26 '20 at 14:15
  • In postman I could see the custom header, but in angular when i use above code I am not getting it. @HrishikeshKale The source for my work is https://github.com/shuaicj/zuul-auth-example When user calls login API he will recieve Authorization token in response headers, Which I could able to see it in postman. While getting response headers in Angular using above mentioned code, I could not see the Authorization field in the header itself. – sreenivas Nov 26 '20 at 14:25
  • @sreenivas can you try to console the response header in your angular application. – Hrishikesh Kale Nov 26 '20 at 15:43
  • @HrishikeshKale I tried printing in console. I am getting these fields body: null ok:true status:200 url:http://localhost:8080 type:4 statusText:OK – sreenivas Nov 27 '20 at 06:29
  • @HrishikeshKale Thanks for the insight. According to [definition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers) wondering how risky it is to expose a token to javascript at client side. Thanks – Jeb50 Jun 12 '21 at 04:03
  • @Jeb50 if you want your own defined header key from the client, you should always expose it from the backend. also never expose or create a token from the client side because it has more chance of a Cross-site scripting attack. – Hrishikesh Kale Jun 12 '21 at 05:36
  • Good point. Could you elaborate a bit on `never expose or create a token from the client side`? Thank you – Jeb50 Jun 12 '21 at 17:46
27

In my case in the POST response I want to have the authorization header because I was having the JWT Token in it. So what I read from this post is the header I we want should be added as an Expose Header from the back-end. So what I did was added the Authorization header to my Exposed Header like this in my filter class.

response.addHeader("Access-Control-Expose-Headers", "Authorization");
response.addHeader("Access-Control-Allow-Headers", "Authorization, X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept, X-Custom-header");
response.addHeader(HEADER_STRING, TOKEN_PREFIX + token); // HEADER_STRING == Authorization

And at my Angular Side

In the Component.

this.authenticationService.login(this.f.email.value, this.f.password.value)
  .pipe(first())
  .subscribe(
    (data: HttpResponse<any>) => {
      console.log(data.headers.get('authorization'));
    },
    error => {
      this.loading = false;
    });

At my Service Side.

return this.http.post<any>(Constants.BASE_URL + 'login', {username: username, password: password},
  {observe: 'response' as 'body'})
  .pipe(map(user => {
       return user;
  }));
Root
  • 955
  • 1
  • 16
  • 39
22

You should use the new HttpClient. You can find more information here.

http
  .get<any>('url', {observe: 'response'})
  .subscribe(resp => {
    console.log(resp.headers.get('X-Token'));
  });
17

As Hrishikesh Kale has explained we need to pass the Access-Control-Expose-Headers.

Here how we can do it in the WebAPI/MVC environment:

protected void Application_BeginRequest()
        {
            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                //These headers are handling the "pre-flight" OPTIONS call sent by the browser
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "*");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "http://localhost:4200");
                HttpContext.Current.Response.AddHeader("Access-Control-Expose-Headers", "TestHeaderToExpose");
                HttpContext.Current.Response.End();
            }
        }

Another way is we can add code as below in the webApiconfig.cs file.

config.EnableCors(new EnableCorsAttribute("", headers: "", methods: "*",exposedHeaders: "TestHeaderToExpose") { SupportsCredentials = true });

**We can add custom headers in the web.config file as below. *

<httpProtocol>
   <customHeaders>
      <add name="Access-Control-Expose-Headers" value="TestHeaderToExpose" />
   </customHeaders>
</httpProtocol>

we can create an attribute and decore the method with the attribute.

Happy Coding !!

David
  • 33,444
  • 11
  • 80
  • 118
Trilok Pathak
  • 2,931
  • 4
  • 28
  • 34
11

You can get data from post response Headers in this way (Angular 6):

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

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
  observe: 'response' as 'response'
};

this.http.post(link,body,httpOptions).subscribe((res: HttpResponse<any>) => {
  console.log(res.headers.get('token-key-name'));
})
Pritam Parker
  • 111
  • 1
  • 3
2

You can get headers using below code

let main_headers = {}
this.http.post(url,
  {email: this.username, password: this.password},
  {'headers' : new HttpHeaders ({'Content-Type' : 'application/json'}), 'responseType': 'text', observe:'response'})
  .subscribe(response => {
    const keys = response.headers.keys();
    let headers = keys.map(key => {
      `${key}: ${response.headers.get(key)}`
        main_headers[key] = response.headers.get(key)
       }
      );
  });

later we can get the required header form the json object.

header_list['X-Token']
Gurudath BN
  • 1,391
  • 20
  • 21
1

Angular 7 Service:

    this.http.post(environment.urlRest + '/my-operation',body, { headers: headers, observe: 'response'});
    
Component:
    this.myService.myfunction().subscribe(
          (res: HttpResponse) => {
              console.log(res.headers.get('x-token'));
                }  ,
        error =>{
        }) 
    
Lauris
  • 11
  • 1
1

Try this simple code.

1. Components side code: to get both body and header property. Here there's a token in body and Authorization in the header.

loginUser() {
    this.userService.loginTest(this.loginCred).
    subscribe(res => {
        let output1 = res;
        console.log(output1.body.token);
        console.log(output1.headers.get('Authorization'));
    })
}

2. Service side code: sending login data in the body and observe the response in Observable any which be subscribed in the component side.

loginTest(loginCred: LoginParams): Observable<any> {
    const header1= {'Content-Type':'application/json',};
    const body =  JSON.stringify(loginCred);
    return this.http.post<any>(this.baseURL+'signin',body,{
        headers: header1,
        observe: 'response',
        responseType: 'json'
    });
}
xKobalt
  • 1,498
  • 2
  • 13
  • 19
A.K.J.94
  • 492
  • 6
  • 14
0

I had to do the following to get the headers to appear in SPA Angular application when GETting them from ASP.NET Core service:

var builder = WebApplication.CreateBuilder(args);

services.AddCors(options =>
{
    options.AddPolicy("MyExposeResponseHeadersPolicy",
        builder =>
        {
            builder.WithOrigins("https://*.example.com")
                   .WithExposedHeaders("x-custom-header");
        });
});

builder.Services.AddControllers();

var app = builder.Build();
Eternal21
  • 4,190
  • 2
  • 48
  • 63