由于问题的标题是“检索所有标题”,因此我想对此添加一个答案。
HttpClient 方法返回的HttpResponseMessage 有两个标头属性:
两个对象都实现了IEnumerable<KeyValuePair<string, IEnumerable<string>>,因此您可以轻松地将所有标头与以下内容结合起来:
var responseMessage = await httpClient.GetAsync(url);
var headers = responseMessage.Headers.Concat(responseMessage.Content.Headers);
// headers has type IEnumerable<KeyValuePair<String,IEnumerable<String>>>
它是一个可枚举的名称集和多个值的原因是因为 一些 HTTP 标头(如 Set-Cookie)可以在响应中重复(即使大多数其他标头只能出现一次 - 但软件应该优雅地处理返回无效标头的违反 RFC 的网络服务器)。
生成所有标题的string:
我们可以使用单个 Linq 表达式生成一个扁平的标题字符串:
- 使用
Concat 组合HttpResponseMessage.Headers 和HttpResponseMessage.Content.Headers。
- 不要使用
Union,因为这样不会保留所有标题。
- (作为个人风格偏好,当我将两个
IEnumerable<T> 对象连接在一起时,我从Enumerable.Empty<T>() 开始以获得视觉上对称的结果 - 不是出于性能或任何其他原因)。
- 在每个 Headers 集合上使用
.SelectMany 以展平每个集合在连接它们的展平结果。
- 将
Aggregate 与StringBuilder 结合使用可有效生成string 表示。
像这样:
HttpResponseMessage resp = await httpClient.GetAsync( url );
String allHeaders = Enumerable
.Empty<(String name, String value)>()
// Add the main Response headers as a flat list of value-tuples with potentially duplicate `name` values:
.Concat(
resp.Headers
.SelectMany( kvp => kvp.Value
.Select( v => ( name: kvp.Key, value: v ) )
)
)
// Concat with the content-specific headers as a flat list of value-tuples with potentially duplicate `name` values:
.Concat(
resp.Content.Headers
.SelectMany( kvp => kvp.Value
.Select( v => ( name: kvp.Key, value: v ) )
)
)
// Render to a string:
.Aggregate(
seed: new StringBuilder(),
func: ( sb, pair ) => sb.Append( pair.name ).Append( ": " ).Append( pair.value ).AppendLine(),
resultSelector: sb => sb.ToString()
);
将所有标题加载到NameValueCollection:
另一种选择是使用 .NET Framework 1.1 中的经典 NameValueCollection 类,它支持具有多个值的键(实际上,它在经典 ASP.NET WebForms 中用于此目的):
像这样:
HttpResponseMessage resp = await httpClient.GetAsync( url );
NameValueCollection allHeaders = Enumerable
.Empty<(String name, String value)>()
// Add the main Response headers as a flat list of value-tuples with potentially duplicate `name` values:
.Concat(
resp.Headers
.SelectMany( kvp => kvp.Value
.Select( v => ( name: kvp.Key, value: v ) )
)
)
// Concat with the content-specific headers as a flat list of value-tuples with potentially duplicate `name` values:
.Concat(
resp.Content.Headers
.SelectMany( kvp => kvp.Value
.Select( v => ( name: kvp.Key, value: v ) )
)
)
.Aggregate(
seed: new NameValueCollection(),
func: ( nvc, pair ) => { nvc.Add( pair.name, pair.value ); return nvc; },
resultSelector: nvc => nvc
);