Angular HttpClient.get() 未返回完整响应标头

问题描述 投票:0回答:4

我使用 HttpClient.get() 从 Angular 9 应用程序调用 REST 服务,但没有看到响应标头的完整列表。我知道该服务正在发送它们,因为:

  1. 我可以在浏览器调试器 Network=> headers 中看到它们(见图)

  1. 当我使用 Java 应用程序访问同一个 REST 服务时,它会返回完整的标头,总共大约有十几个:

java.net.http.HttpHeaders@1627d314 { {access-control-allow-origin=[*], 年龄=[0],连接=[保持活动],内容长度=[1207], content-type=[application/json], date=[2020 年 7 月 7 日星期二 05:11:45 GMT] <...etc>

我从 Angular HttpClient.get() 得到的只是 header.keys() 中的一项:

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

headerKeys:
[
  "content-type: application/json"
]

我创建了一个小示例应用程序来演示该问题。以下是关键组件:

app.modules.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { TesterComponent } from './tester/tester.component';

@NgModule({
  declarations: [
    AppComponent,
    TesterComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

测试器.component.ts:

import { Component, OnInit } from '@angular/core';
import { HttpHeaders, HttpParams, HttpResponse, HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Component({
  selector: 'app-tester',
  templateUrl: './tester.component.html',
  styleUrls: ['./tester.component.css']
})
export class TesterComponent implements OnInit {

  _url: string = "https://api.nasa.gov/planetary/apod";
  _api_key: string="DEMO_KEY";

  //
_title: string;
_date: string;

  constructor(private _httpClient: HttpClient) { }

  ngOnInit(): void {

    this.GetData(this._url).subscribe(()  =>
    {
       // do other stuff
     
    });
  }

  
 sendGetRequest(getUrl: string, headers: HttpHeaders, urlParams: HttpParams) : Observable<HttpResponse<Object>>{
    return this._httpClient.get<HttpResponse<Object>>(getUrl, {headers: headers, params: urlParams, observe: 'response'});
  }


  GetData(url: string)
  {

    const params = new HttpParams()
      .set("api_key", this._api_key);

    return this.sendGetRequest(url, headers, params).pipe(
      
      tap( response =>
      {
      
      console.log("returning data");

      if (response.headers)
      {
        console.log('headers', response.headers);
      }

      const keys = response.headers.keys();

      if (keys)
      {
        const headerKeys = keys.map(key =>
          `${key}: ${response.headers.get(key)}`);

        console.log('headerKeys', headerKeys);
      }

      this._date = response.body['date'];
      this._title = response.body['title'];
    },
    err => {
      console.log(err);
    }
    
      ));
  }

}

附录: 为了进一步说明这个问题,这里有一个小型 Java 11 程序,它使用相同的凭据“完全”调用相同的 REST API。您可以从输出中看到 REST API 正在发回所有标头响应信息。问题仍然存在,为什么 Angular 程序无法准确地调用相同的 REST API 查看完整的响应标头?通话中是否缺少某些设置/标志/巫毒? Java 11 应用程序: import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; public class MainClass { public static void main(String[] args) { String api_key = "DEMO_KEY"; String uri = "https://api.nasa.gov/planetary/apod"; uri += "?api_key=" + api_key; HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder().uri(URI.create(uri)).build(); HttpResponse<String> response = null; try { response = client.send(request, BodyHandlers.ofString()); } catch (Exception e) { e.printStackTrace(); } System.out.println("------------------"); System.out.println("response.headers: " + response.headers()); System.out.println(response.body()); System.out.println("------------------"); } }

Java 应用程序的输出(response.header 仅出于简洁目的):

response.headers: java.net.http.HttpHeaders@96f4f3fc {
{access-control-allow-origin=[*],年龄=[0],连接=[keep-alive],
内容长度=[1302],内容类型=[应用程序/json],日期=[星期三,08
2020 年 7 月 17:13:42 GMT],服务器=[openresty],
严格传输安全=[最大年龄=31536000;预载],
变化=[接受编码],via=[http/1.1 api-umbrella
(ApacheTrafficServer [cMsSf ])], x-cache=[MISS],
x-ratelimit-limit=[40], x-ratelimit-remaining=[39]} }

感谢您的帮助!

您需要设置

Access-Control-Expose-Headers
angular header httpclient response
4个回答
4
投票
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers


默认情况下,仅公开 7 个 CORS 安全列表响应标头:

缓存控制

内容语言
  • 内容长度
  • 内容类型
  • 过期
  • 最后修改时间
  • 杂注
  • 您将在网络选项卡中看到其他标头,但 JavaScript 将无法访问它们,除非它们位于
  • Access-Control-Expose-Headers
标头中。

这是 Axios 的一个类似问题,这是 4 年前不同的 javascript HTTP 库,具有相同的答案:

Axios 可以访问响应头字段

And 和 2.5 年前的 Angular 从 API 响应中读取响应标头 - Angular 5 + TypeScript

更新:由于您正在调用一个我认为您不拥有的API(https://api.nasa.gov/),因此如果您需要阅读,您必须让NASA添加标头

Access-Control-Expose-Headers: X-RateLimit-Limit, X-RateLimit-Remaining

您客户端中的那些标头。 您的另一个选择是创建一个代理服务器,而不是调用 NASA,您可以调用自己的服务器,该服务器将调用 NASA 并且可以包含您的速率限制标头。

    

为了获取 HTTP 响应的完整标头以及内容,您应该在发出请求时传递另一个名为

observe

0
投票

http .get<MyJsonData>('/data.json', {observe: 'response'}) .subscribe(response => { response.headers.keys().map( (key) => console.log(`${key}: ${response.headers.get(key)}`)); });

我花了几个小时进行反复试验才使其发挥作用。在我看来,Chrome 和 javascript 的交互方式很古怪。

0
投票

但是 Chrome 将其显示为“X-Document-Id”。

JavaScript 看不到标题

除非我公开“X-Document-Id”

,如下所示:

@CrossOrigin( origins = { "http://localhost:4200", "https://www.xxxxxxx.com" }, allowCredentials = "true", exposedHeaders = { "X-Document-Id", "x-document-id" } ) 但是当我转储 JSON.stringify( resp.headers.keys() ) 时,控制台显示:

[
    "cache-control",
    "content-length",
    "content-type",
    "x-document-id"
]

And when I dump JSON.stringify( resp.headers ) the console displays: { "normalizedNames": {}, "lazyUpdate": null, "lazyInit": null, "headers": {} }

系统的某些部分真的区分大小写而其他部分不区分大小写吗?

来自 mozila

文档

-2
投票

“Access-Control-Expose-Headers 响应标头允许服务器指示哪些响应标头应可供浏览器中运行的脚本使用,以响应跨源请求。 默认情况下仅公开 CORS 安全列表中的响应标头。为了使客户端能够访问其他标头,服务器必须使用 Access-Control-Expose-Headers 标头列出它们。”

您需要配置服务器端api(core.api,exc')

显式允许您想要向客户端公开的标头

services.AddCors(options => { options.AddPolicy("AllowAll", builder => { builder.AllowAnyHeader() .AllowAnyOrigin() .WithExposedHeaders("Content-Range"); }); });

配置后,您将看到标题“content-Range”

content-range: Categories 0-2/4

它将在 JavaScript 代码中可用

© www.soinside.com 2019 - 2024. All rights reserved.