【问题标题】:System.Net.Http.HttpClient with AutomaticDecompression and GetAsync (timeout) vs GetStringAsync (workingSystem.Net.Http.HttpClient with AutomaticDecompression and GetAsync (timeout) vs GetStringAsync (working
【发布时间】:2016-09-01 12:37:41
【问题描述】:

我有以下代码使用 Xamarin 和 Android 设备向 REST API 发出请求:

public class ApiBase
{
  HttpClient m_HttpClient;

  public ApiBase(string baseAddress, string username, string password)
  {
    if (!baseAddress.EndsWith("/"))
    {
      baseAddress += "/";
    }
    var handler = new HttpClientHandler();
    if (handler.SupportsAutomaticDecompression)
    {
      handler.AutomaticDecompression = DecompressionMethods.GZip;
    }
    m_HttpClient = new HttpClient(handler);
    m_HttpClient.BaseAddress = new Uri(baseAddress);
    var credentialsString = Convert.ToBase64String(Encoding.UTF8.GetBytes(username + ":" + password));
    m_HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", credentialsString);
    m_HttpClient.Timeout = new TimeSpan(0, 0, 30);
  }

  protected async Task<XElement> HttpGetAsync(string method)
  {
    try
    {

      HttpResponseMessage response = await m_HttpClient.GetAsync(method);
      if (response.IsSuccessStatusCode)
      {
        // the request was successful, parse the returned string as xml and return the XElement
        var xml = await response.Content.ReadAsAsync<XElement>();
        return xml;
      }
      // the request was not successful -> return null
      else
      {
        return null;
      }
    }
    // some exception occured -> return null
    catch (Exception)
    {
      return null;
    }
  }
}

如果我有这样的情况,对 HttpGetAsync 的第一次和第二次调用可以完美运行,但从第三次开始,GetAsyncstalls 并最终由于超时而引发异常。我连续发送这些调用,它们中没有两个同时运行,因为需要前一个调用的结果来决定下一个调用。 我尝试使用应用程序数据包捕获来查看请求和响应,以确定我是否发送了错误的请求。但是看起来最终失败的请求甚至从未发送过。

通过实验我发现如果不设置AutomaticDecompression,一切正常。

如果我将HttpGetAsync 方法更改为此,它也可以正常工作:

protected async Task<XElement> HttpGetAsync(string method)
{
  try
  {
    // send the request
    var response = await m_HttpClient.GetStringAsync(method);
    if (string.IsNullOrEmpty(response))
    {
      return null;
    }
    var xml = XElement.Parse(response);
    return xml;
  }
  // some exception occured -> return null
  catch (Exception)
  {
    return null;
  }
}

所以基本上使用我 m_HttpClient.GetStringAsync 而不是 m_HttpClient.GetAsync 然后更改它周围的绒毛以使用不同的返回类型。如果我这样做,一切都会顺利进行。

有谁知道为什么GetAsync 不能正常工作(似乎没有发送第三个请求)与AutomaticDecompression,而GetStringAsync 工作完美?

【问题讨论】:

  • HTTP 客户端的错误很少,而且它不使用本机处理程序。我使用更快的现代 Http 客户端。

标签: android xamarin dotnet-httpclient


【解决方案1】:

有关于这个确切问题的错误报告:
https://bugzilla.xamarin.com/show_bug.cgi?id=21477

该错误被标记为已解决,建议的操作是更新到最新的稳定版本。但是还有其他(较新的)错误报告表明相同的东西仍然处于打开状态,例如:
https://bugzilla.xamarin.com/show_bug.cgi?id=34747

我通过像这样实现自己的 HttpHandler 来解决问题:

公共类 DecompressionHttpClientHandler : HttpClientHandler { 受保护的覆盖异步任务 SendAsync(HttpRequestMessage request, CancellationToken cancelToken) { request.Headers.AcceptEncoding.Add(new System.Net.Http.Headers.StringWithQualityHeaderValue("gzip")); var msg = await base.SendAsync(request, cancelToken); if (msg.Content.Headers.ContentEncoding.Contains("gzip")) { varcompressedStream = 等待 msg.Content.ReadAsStreamAsync(); var uncompressedStream = new System.IO.Compression.GZipStream(compressedStream, System.IO.Compression.CompressionMode.Decompress); msg.Content = new StreamContent(uncompressedStream); } 返回味精; } }

请注意,上面的代码只是一个示例,并不是最终解决方案。例如,请求不会被压缩,并且所有标头都将从结果中剥离。但你明白了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-13
    • 2015-12-11
    • 1970-01-01
    • 2022-12-19
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    • 2014-11-21
    相关资源
    最近更新 更多