Angular 4.3.3 HttpClient:如何从响应的 header 中获取值?
Angular 4.3.3 HttpClient : How get value from the header of a response?
(编辑:VS Code;打字稿:2.2.1)
目的是获取请求的响应headers
假设在服务
中使用 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 Angular Documentation
第一个问题是我遇到了 Typescript 错误:
'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() 方法的引用时,我指向这个原型(我使用 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",
};
并且编译成功!但我只收到 body 格式的 json 请求。
此外,为什么我必须放一个?某些字段名称末尾的符号?正如我在 Typescript 网站上看到的那样,这个符号应该只是告诉用户它是可选的?
我还尝试使用所有字段,不带和带?标记
编辑
我尝试了提出的解决方案。对于地图解决方案:
this.http.post(url).map(resp => console.log(resp));
Typescript 编译器告诉 map 不存在,因为它不是 Observable 的一部分
我也试过这个
import { Response } from "@angular/http";
this.http.post(url).post((resp: Response) => resp)
它可以编译,但我收到了不支持的媒体类型响应。
这些解决方案应该适用于 "Http" 但不适用于 "HttpClient".
编辑 2
我还得到了@Supamiu 解决方案不支持的媒体类型,所以这对我的 headers 来说是个错误。因此,上面的第二个解决方案(使用 Response 类型)也应该有效。但就个人而言,我不认为将 "Http" 与 "HttpClient" 混合使用是一种好方法,因此我将保留 Supamiu
的解决方案
您可以观察到完整的回复,而不仅仅是内容。为此,您必须将 observe: response
传递到函数调用的 options
参数中。
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);
});
确实,主要问题是 Typescript 问题。
在post()的代码中,options是直接在参数中声明的,所以,作为一个"anonymous"接口。
解决办法是直接把raw中的options放在参数里面
http.post("url", body, {headers: headers, observe: "response"}).subscribe...
类型转换的主要问题,因此我们可以将 "response" 用作 'body'
我们可以这样处理
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;
});
如果您使用顶部答案中的解决方案并且您无权访问 .keys()
或 response.headers
上的 .get()
,请确保您使用的是获取而不是xhr。
获取请求是默认设置,但如果 xhr-only header 存在,Angular 将使用 xhr (e.x。x-www-form-urlencoded
)。
如果您尝试访问任何自定义响应 header,则必须指定那些 header 以及另一个名为 Access-Control-Expose-Headers 的 header。
有时即使使用上述解决方案,如果是 CORS 请求,您也无法检索自定义 headers。在这种情况下,您需要在服务器端将所需的 headers 列入白名单。
例如:Access-Control-Expose-Headers:X-Total-Count
下面的方法非常适合我(目前 Angular 10)。它还避免设置一些任意文件名,而是从 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]*=((['"]).*?|[^;\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'));
})
正如其他开发人员所说,为了将 headers 和 body 放在一起,您应该以这种方式定义观察者收益的类型:
http.post("url", body, {headers: headers, observe: "response" as "body"})
然后就可以在pip或者订阅区访问body和headers:
http.post("url", body, {headers: headers, observe: "response" as "body"})
.pip(
tap(res => {
// res.headers
// res.body
})
)
.subscribe(res => {
// res.headers
// res.body
})
(编辑:VS Code;打字稿:2.2.1)
目的是获取请求的响应headers
假设在服务
中使用 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 Angular Documentation
第一个问题是我遇到了 Typescript 错误:
'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() 方法的引用时,我指向这个原型(我使用 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",
};
并且编译成功!但我只收到 body 格式的 json 请求。
此外,为什么我必须放一个?某些字段名称末尾的符号?正如我在 Typescript 网站上看到的那样,这个符号应该只是告诉用户它是可选的?
我还尝试使用所有字段,不带和带?标记
编辑
我尝试了
this.http.post(url).map(resp => console.log(resp));
Typescript 编译器告诉 map 不存在,因为它不是 Observable 的一部分
我也试过这个
import { Response } from "@angular/http";
this.http.post(url).post((resp: Response) => resp)
它可以编译,但我收到了不支持的媒体类型响应。 这些解决方案应该适用于 "Http" 但不适用于 "HttpClient".
编辑 2
我还得到了@Supamiu 解决方案不支持的媒体类型,所以这对我的 headers 来说是个错误。因此,上面的第二个解决方案(使用 Response 类型)也应该有效。但就个人而言,我不认为将 "Http" 与 "HttpClient" 混合使用是一种好方法,因此我将保留 Supamiu
的解决方案您可以观察到完整的回复,而不仅仅是内容。为此,您必须将 observe: response
传递到函数调用的 options
参数中。
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);
});
确实,主要问题是 Typescript 问题。
在post()的代码中,options是直接在参数中声明的,所以,作为一个"anonymous"接口。
解决办法是直接把raw中的options放在参数里面
http.post("url", body, {headers: headers, observe: "response"}).subscribe...
类型转换的主要问题,因此我们可以将 "response" 用作 'body'
我们可以这样处理
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;
});
如果您使用顶部答案中的解决方案并且您无权访问 .keys()
或 response.headers
上的 .get()
,请确保您使用的是获取而不是xhr。
获取请求是默认设置,但如果 xhr-only header 存在,Angular 将使用 xhr (e.x。x-www-form-urlencoded
)。
如果您尝试访问任何自定义响应 header,则必须指定那些 header 以及另一个名为 Access-Control-Expose-Headers 的 header。
有时即使使用上述解决方案,如果是 CORS 请求,您也无法检索自定义 headers。在这种情况下,您需要在服务器端将所需的 headers 列入白名单。
例如:Access-Control-Expose-Headers:X-Total-Count
下面的方法非常适合我(目前 Angular 10)。它还避免设置一些任意文件名,而是从 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]*=((['"]).*?|[^;\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'));
})
正如其他开发人员所说,为了将 headers 和 body 放在一起,您应该以这种方式定义观察者收益的类型:
http.post("url", body, {headers: headers, observe: "response" as "body"})
然后就可以在pip或者订阅区访问body和headers:
http.post("url", body, {headers: headers, observe: "response" as "body"})
.pip(
tap(res => {
// res.headers
// res.body
})
)
.subscribe(res => {
// res.headers
// res.body
})