51

I am trying to get into angular lately. I have a paginated request.

const myParams = new HttpParams().set('page', page.toString()).set('size', size.toString());
this.http.get<HttpResponse<User[]>>('https://localhost:8443/user/', {
      headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
      params: myParams,
      observe: 'response'
    }).suscribe((response: HttpResponse<User[]>) => this.data = response.body);

The total count of elements in the DB is transfered to the Client in the X-Total-Count header. i tried to read it like that:

.suscribe((response: HttpResponse<User[]>) => {
    this.data = response.body;
    this.totalCount = response.headers.get('X-Total-Count');
});

But this does not work. It turns out that response.headers only includes a subset of the real http-response-headers.

this is what the headers object looks like

"headers": {
    "normalizedNames": {},
    "lazyUpdate": null
  }

I am sure that X-Total-Count has been sent. Firefox devtools show it. Could you please tell me how to include it into the response?

enter image description here

UPDATE

This question differs from the one that has been identified as a duplicate in the following way: I have not been asking about how to inspect the full httpResponse. I figured that out on my own. I have been asking about why the headers attribute of the Response is not complete.

Doug Amos
  • 4,243
  • 1
  • 22
  • 23
Mr.H.
  • 965
  • 1
  • 10
  • 18
  • 3
    I am sorry to inform you that this is not a replica of the post you have mentioned. As you can see, I have used the approach from the answer you have linked. `observe: 'response'`. My Problem is that `response.headers` does not contain **all** the headers that have been sent by the backend. – Mr.H. Sep 21 '18 at 12:50
  • Sorry, you are right! – Tsvetan Ganev Sep 21 '18 at 13:03

5 Answers5

105

CORS requests only expose 6 safelisted headers : Cache-Control Content-Language Content-Type Expires Last-Modified & Pragma.

In order to access custom headers with a CORS request, the server has to explicitly whitelist them. This can be done by sending the response header: Access-Control-Expose-Headers

For example: Access-Control-Expose-Headers: X-Total-Count, X-Paging-PageSize

MDN Source

Matthieu Riegler
  • 31,918
  • 20
  • 95
  • 134
Tsvetan Ganev
  • 8,246
  • 4
  • 26
  • 43
  • 4
    holy lord what a rathole i just crawled out of. thank you for this answer. if you're using flask CORS, just set the expose header options and you're golden – activedecay Nov 10 '21 at 16:10
  • 3
    In my case I added this on the ASP.NET Core server side CORS policy setup services.AddCors(o => o.AddPolicy("CorsPolicy", builder => { builder .AllowAnyHeader() .WithOrigins(origins) .WithExposedHeaders(new string[] { "X-Total-Count" }) .AllowCredentials(); })); – John McCann Mar 31 '22 at 15:31
  • 1
    For those of you that are looking how to add thes headers to a (.NET 6) ASP.NET Web API: use .WithExposedHeaders("X-Total-Count") on the CORS policy. – Quido Sep 28 '22 at 08:41
23

The headers in an HttpResponse object are lazy-loaded, so headers will appear to be empty until you force the values to be loaded. Try calling response.headers.keys() to see all available header names. By the way, this also forces all values to be loaded into the map response.headers.headers.

Gyromite
  • 769
  • 6
  • 16
2

Try to add withCredentials: true to the http options object.

2

As Tsvetan Ganev stated before, if this is CORS request you need to explicity expose required headers in Access-Control-Expose-Headers header by name. To achieve this you need to configure your application server, for example in Spring while using WebMvcConfigurer you can expose headers like:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry
                .addMapping("/**")
                .allowedOrigins("*")
                .exposedHeaders("X-Total-Count")
                .allowedMethods("*");
    }
}

Using this configuration, your browser, beyond 7 default headers:

  • Cache-Control
  • Content-Language
  • Content-Length
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

Will expose X-Total-Count header for your application as well.

bladekp
  • 1,529
  • 22
  • 29
0

In my case, Postman was able to fetch the custom "Authorization" header, but Angular wasn't. I solved it by explicitly exposing the custom header

@Bean
public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    // vvv
    config.addExposedHeader(HttpHeaders.AUTHORIZATION);
    // ^^^
    config.addAllowedMethod(HttpMethod.OPTIONS);
    config.addAllowedMethod(HttpMethod.GET);
    config.addAllowedMethod(HttpMethod.POST);
    config.addAllowedMethod(HttpMethod.PUT);
    config.addAllowedMethod(HttpMethod.PATCH);
    config.addAllowedMethod(HttpMethod.DELETE);
    config.setMaxAge(1800L);
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}
Richard
  • 556
  • 5
  • 12