【问题标题】:Adding HttpClient headers generates a FormatException with some values添加 HttpClient 标头会生成带有一些值的 FormatException
【发布时间】:2012-11-02 15:16:36
【问题描述】:

这发生在针对 Google Cloud Messaging 进行编码的上下文中,但适用于其他地方。

考虑以下几点:

var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("key=XXX");

var http = new HttpClient();
http.DefaultRequestHeaders.Add("Authorization", "key=XXX");

两者都会产生 FormatException:

System.FormatException : value key=XXX' 的格式无效。

解决办法是去掉等号。

  1. 深入研究反射器表明,在添加新标头值时会运行大量验证和解析代码。为什么这一切都是必要的?这位客户不应该让开我们的路吗?

  2. 如何转义等号以使添加此值成功?

【问题讨论】:

  • @SamIam 尝试向 GCN API 发布消息 - 这需要使用上面显示的格式作为标头发送身份验证信息。但是,这是一个关于 HttpClient 标头的允许值的更普遍的问题。

标签: c# dotnet-httpclient google-cloud-messaging


【解决方案1】:

不确定是否仍然相关,但我最近遇到了同样的问题,并且能够通过调用不同的方法来添加标题信息来解决它:

var http = new HttpClient();
http.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=XXX");

【讨论】:

  • 如果你不希望它在默认标头中,也可以在 HttpRequestMessage 上调用此方法
  • 将此标记为答案,尽管我仍然不明白为什么其他方法在验证时失败(如果它是有效值)。
  • 另外,在 Windows 10 的 httpclient 中似乎没有帮助
  • 我看到这是一个旧线程,但我刚刚遇到了这个问题@EdSykes 并尝试改用HttpRequestMessage 并没有任何区别。 TryAddWithoutValidation 方法对我有用。
【解决方案2】:

对于“为什么所有这些(解析和验证)都是必要的”问题,答案是:它在 HTTP 标准中定义。

HTTP/1.1RFC2617中,认证头(如WWW-Authenticate和Authorization)的值有两部分:方案部分和参数部分

对于HTTP Basic Authentication,scheme是“Basic”,参数可能类似于"QWxhZGRpbjpvcGVuIHNlc2FtZQ==",所以整个header变成:

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

这就是您的“key=XXX”没有通过验证的原因,因为它缺少方案部分。

【讨论】:

  • 在参数部分有 key=value 是有效的。见stackoverflow.com/a/19512506/55732
  • @Kurlak: key=value 仅对“auth-param”部分有效,对整个“credentials”部分无效。 CodeCaster 的解释不太对。
  • 我实际上使用Bearer 作为方案,但它仍然向我显示错误。
  • 我在 Bearer 之后有一个空格,例如“Bearer”,这导致了问题。我在下面看到了@Robert Stokes 的回答,帮助我看到了它。
【解决方案3】:

当我在 Authorization 标头的末尾添加一个空格时,我遇到了这个错误并偶然发现了这篇文章。

this.bearerAuthHttpClient.DefaultRequestHeaders.Add("Authorization ", $"Bearer {token}");

授权后可以看到有问题的“ ”。

我花了大约 15 分钟才看到我的错字...

【讨论】:

    【解决方案4】:

    我通过按以下方式设置 Authorization 标头解决了这个异常(我的 FormatException 由值中的逗号引起):

    var authenticationHeaderValue = new AuthenticationHeaderValue("some scheme", "some value");
    client.DefaultRequestHeaders.Authorization = authenticationHeaderValue;
    

    【讨论】:

      【解决方案5】:

      今天早上我在处理一个不完全遵循 HTTP 规范的外部 API 时遇到了几个问题。

      作为我发布的一部分,他们想要Content-TypeContent-Disposition,它们不能添加到HttpClient 对象中。要添加这些标题,您需要创建一个HttpRequestMessage。在那里,您需要将标题添加到 Content 属性。

      private HttpRequestMessage GetPostMessage(string uri, string contentType,
                                                string fileName, Stream content)
      {    
          var request = new HttpRequestMessage
          {
              Content = new StreamContent(content),
              RequestUri = new Uri(uri),
              Method = HttpMethod.Post
          };
      
          // contentType = "video/mp4"
          request.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
      
          //Need TryAddWithoutValidation because of the equals sign in the value.
          request.Content
                 .Headers
                 .TryAddWithoutValidation("Content-Disposition",
                                          $"attachment; filename=\"{Path.GetFileName(fileName)}\"");
      
          // If there is no equals sign in your content disposition, this will work:
          // request.Content.Headers.ContentDisposition = 
          //    new ContentDispositionHeaderValue($"attachment; \"{Path.GetFileName(fileName)}\"");
      
          return request;
      }
      

      【讨论】:

        【解决方案6】:

        在我的例子中,我从 byte[] RowVersion SQL 字段生成 ETags 字符串值。 所以我需要添加 wrap 生成的。即 AAAAAAAAF5s= string inside " 如下...

                var eTag = department.RowVersion.ToETagString();
        
                httpClient.DefaultRequestHeaders.Add(Microsoft.Net.Http.Headers.HeaderNames.IfMatch, $"\"{eTag}\"")
        
        
            public class DepartmentForHandleDto
            {
                public string Name { get; set; }
                public string GroupName { get; set; }
                public byte[] RowVersion { get; set; }
            }
        
            public static class ByteArrayExtensions
            {
                public static string ToETagString(this byte[] byteArray)
                {
                    return Convert.ToBase64String(byteArray != null && byteArray.Length > 0 ? byteArray : new byte[8]);                    
                }
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-05-11
          • 1970-01-01
          • 2017-12-30
          • 2012-08-14
          相关资源
          最近更新 更多