角度4.3.3 HttpClient: 如何从响应头获取值?

(编辑器: VS 代码; 类型: 2.2.1)

其目的是获取请求响应的头部

假设在服务中使用 HttpClient 发出 POST 请求

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


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


@Injectable()
export class MyHttpClientService {
const url = 'url';


const body = {
body: 'the body'
};


const headers = 'headers made with HttpHeaders';


const options = {
headers: headers,
observe: "response", // to display the full response
responseType: "json"
};


return this.http.post(sessionUrl, body, options)
.subscribe(response => {
console.log(response);
return response;
}, err => {
throw err;
});
}

HttpClient 角度文档

第一个问题是我有一个类型错误:

'Argument of type '{
headers: HttpHeaders;
observe: string;
responseType: string;
}' is not assignable to parameter of type'{
headers?: HttpHeaders;
observe?: "body";
params?: HttpParams; reportProgress?: boolean;
respons...'.


Types of property 'observe' are incompatible.
Type 'string' is not assignable to type '"body"'.'
at: '51,49' source: 'ts'

实际上,当我转到 post ()方法的 ref 时,我指向这个原型(我使用 VS 代码)

post(url: string, body: any | null, options: {
headers?: HttpHeaders;
observe?: 'body';
params?: HttpParams;
reportProgress?: boolean;
responseType: 'arraybuffer';
withCredentials?: boolean;
}): Observable<ArrayBuffer>;

但是我想要这个重载的方法:

post(url: string, body: any | null, options: {
headers?: HttpHeaders;
observe: 'response';
params?: HttpParams;
reportProgress?: boolean;
responseType?: 'json';
withCredentials?: boolean;
}): Observable<HttpResponse<Object>>;

因此,我尝试用这个结构修复这个错误:

  const options = {
headers: headers,
"observe?": "response",
"responseType?": "json",
};

它编译了! 但是我只得到了 json 格式的 body 请求。

另外,为什么我要放一个?某些字段名称末尾的符号?正如我在 Typecript 网站上看到的,这个符号应该只是告诉用户,它是可选的?

我还尝试使用所有字段,无标记和? 标记

编辑

我尝试了 角度4从 API 响应中获取头信息提出的解决方案。对于地图解决方案:

this.http.post(url).map(resp => console.log(resp));

类型脚本编译器告诉映射不存在,因为它不是可观察的一部分

我也试过这个

import { Response } from "@angular/http";


this.http.post(url).post((resp: Response) => resp)

它可以编译,但是我得到一个不受支持的 Media Type 响应。 这些解决方案应该适用于“ Http”,但不适用于“ HttpClient”。

编辑2

我还得到一个不支持的媒体类型与@Supamiu 解决方案,所以它将是一个错误,我的标题。因此上面的第二个解决方案(使用 Response 类型)也应该可以工作。但就个人而言,我不认为把“ Http”和“ httpClient”混为一谈是一个好办法,因此我将保留 Supamiu 的解决方案

134774 次浏览

You can observe the full response instead of the content only. To do so, you have to pass observe: response into the options parameter of the function call.

http
.get<MyJsonData>('/data.json', {observe: 'response'})
.subscribe(resp => {
// Here, resp is of type HttpResponse<MyJsonData>.
// You can inspect its headers:
console.log(resp.headers.get('X-Custom-Header'));
// And access the body directly, which is typed as MyJsonData as requested.
console.log(resp.body.someField);
});

See HttpClient's documentation

Indeed, the main problem was a Typescript problem.

In the code of post(), options was declared directly in the parameters, so, as an "anonymous" interface.

The solution was to put directly the options in raw inside the parameters

http.post("url", body, {headers: headers, observe: "response"}).subscribe...

main problem of typecast so we can use "response" as 'body'

we can handle like

const options = {
headers: headers,
observe: "response" as 'body', // to display the full response & as 'body' for type cast
responseType: "json"
};


return this.http.post(sessionUrl, body, options)
.subscribe(response => {
console.log(response);
return response;
}, err => {
throw err;
});

If you use the solution from the top answer and you don't have access to .keys() or .get() on response.headers, make sure that you're using fetch rather than xhr.

Fetch requests are the default, but Angular will use xhr if xhr-only headers are present (e.x. x-www-form-urlencoded).

If you are trying to access any custom response headers, then you have to specify those headers with another header called Access-Control-Expose-Headers.

Some times even with the above solution you can't retrieve custom headers if it is CORS request. In that case you need to whitelist desired headers in server side.

For Example: Access-Control-Expose-Headers: X-Total-Count

The below method worked perfectly for me (currently Angular 10). It also avoids setting some arbitary filename, instead it gets the filename from the content-disposition header.

this._httpClient.get("api/FileDownload/GetFile", { responseType: 'blob' as 'json', observe: 'response' }).subscribe(response =>  {
/* Get filename from Content-Disposition header */
var filename = "";
var disposition = response.headers.get('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
}
// This does the trick
var a = document.createElement('a');
a.href = window.URL.createObjectURL(response.body);
a.download = filename;
a.dispatchEvent(new MouseEvent('click'));
})

As other developers said, for getting headers and body together you should define the type of observer yield in this way:

http.post("url", body, {headers: headers, observe: "response" as "body"})

Then you can access to body and headers in pip or a subscribe area:

http.post("url", body, {headers: headers, observe: "response" as "body"})
.pip(
tap(res => {
// res.headers
// res.body
})
)
.subscribe(res => {
// res.headers
// res.body
})