35

目前,我正在研究 API 包装器。如果我发送 bad Consumer Key,服务器将返回标题中的Status内容。403 Forbidden它还将传递自定义标题。我如何实际检索这些自定义标头?

这是从服务器接收到的响应。

Cache-Control: private
Date: Wed,  01 May 2013 14:36:17 GMT
P3P: policyref="/w3c/p3p.xml",  CP="ALL CURa ADMa DEVa OUR IND UNI COM NAV INT STA PRE"
Server: Apache/2.2.23 (Amazon)
Status: 403 Forbidden
X-Error: Invalid consumer key.
X-Error-Code: 152
X-Powered-By: PHP/5.3.20
Connection: keep-alive

我需要检索X-Errorand X-Error-Code。目前,我正在使用HttpClient类来处理请求。如果我在 VS Studio 2012 的 Quick Watch 下看到标题响应,我会发现它是这样的

((System.Net.Http.Headers.HttpHeaders)(response.Headers)).headerStore["X-Error-Code"].ParsedValue

有没有其他方法可以做到这一点?

编辑: headerStore无法通过代码访问,因为这是私有字段。我只能通过“快速观看”窗口访问它。

这是我的请求片段:

var response = await _httpClient.PostAsync("/v3/oauth/request", content);
4

5 回答 5

48

好吧,HttpResponseMessage.Headers返回一个HttpResponseHeaders参考,所以你应该可以使用GetValues()

string error = response.Headers.GetValues("X-Error").FirstOrDefault();
string errorCode = response.Headers.GetValues("X-Error-Code").FirstOrDefault();
于 2013-05-01T15:10:19.283 回答
35

由于问题的标题是“检索所有标题”,因此我想对此添加一个答案。

HttpResponseMessage方法返回的有HttpClient两个头属性:

  • HttpResponseMessage.Headers是一个HttpResponseHeaders带有通用响应头的
  • HttpResponseMessage.Content.HeadersHttpContentHeaders具有特定于内容的标题,例如Content-Type

这两个对象都实现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.HeadersHttpResponseMessage.Content.Headers
    • 不要使用Union,因为这不会保留所有标题。
    • (作为个人风格偏好,当我将两个IEnumerable<T>对象连接在一起时,我从Enumerable.Empty<T>()视觉上对称的结果开始 - 不是出于性能或任何其他原因)。
  • 在连接它们的扁平结果之前.SelectMany,在每个 Headers 集合上使用以扁平化每个集合。
  • Aggregate与 a一起使用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

另一种选择是使用NameValueCollection.NET Framework 1.1 中的经典类,它支持具有多个值的键(实际上,它在 Classic 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
        );
于 2017-01-24T19:02:54.853 回答
13

只是我在尝试查找不存在的标头时发现的一个问题。您应该使用 TryGetValues 而不是 GetValues,因为在运行时如果找不到标头,它将引发异常。你会使用类似这样的代码:

IEnumerable<string> cookieHeader; 
response.Headers.TryGetValues("Set-Cookie", out cookieHeader);
于 2014-03-10T14:48:53.637 回答
4

有点笨重,但简单易懂..

            System.Diagnostics.Debug.Write("----- CLIENT HEADERS -----" + Environment.NewLine);
            foreach (KeyValuePair<string, IEnumerable<string>> myHeader in myHttpClient.DefaultRequestHeaders)
            {
                System.Diagnostics.Debug.Write(myHeader.Key + Environment.NewLine);
                foreach(string myValue in myHeader.Value)
                {
                    System.Diagnostics.Debug.Write("\t" + myValue + Environment.NewLine);
                }
            }

            System.Diagnostics.Debug.Write("----- MESSAGE HEADERS -----" + Environment.NewLine);
            foreach (KeyValuePair<string, IEnumerable<string>> myHeader in myHttpRequestMessage.Headers)
            {
                System.Diagnostics.Debug.Write(myHeader.Key + Environment.NewLine);
                foreach (string myValue in myHeader.Value)
                {
                    System.Diagnostics.Debug.Write("\t" + myValue + Environment.NewLine);
                }
            }

            System.Diagnostics.Debug.Write("----- CONTENT HEADERS -----" + Environment.NewLine);
            foreach (KeyValuePair<string, IEnumerable<string>> myHeader in myHttpRequestMessage.Content.Headers)
            {
                System.Diagnostics.Debug.Write(myHeader.Key + Environment.NewLine);
                foreach (string myValue in myHeader.Value)
                {
                    System.Diagnostics.Debug.Write("\t" + myValue + Environment.NewLine);
                }
            }
于 2019-07-03T12:40:51.043 回答
0

这对我有用:

(String[])response.Headers.GetValues("X-Error"))[0]
于 2017-09-07T21:29:50.650 回答