2016-09-01 2 views
0

У меня есть следующий код, чтобы сделать запросы к REST API, с помощью Xamarin и Android устройства:System.Net.Http.HttpClient с AutomaticDecompression и GetAsync (тайм-аут) против GetStringAsync (рабочий

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 работают отлично, но с третьего на GetAsync киосках и, в конце концов, выдает исключение из-за таймаута. Я посылаю эти вызовы последовательно, их нет одновременно, поскольку результаты предыдущего вызова необходимы для принятия решения о следующем вызове. Я попытался использовать приложение Packet Capture, чтобы посмотреть на запросы и ответы, чтобы узнать, отправляю ли я прямой запрос. Но похоже, что запрос, который терпит неудачу, никогда не отправляется.

Через эксперименты я узнал, что все работает нормально, если не установить 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 не работает должным образом (не похоже, чтобы отправить запрос на 3-й) с AutomaticDecompression, где, как GetStringAsync работает безупречно?

+0

Существует несколько ошибок с HTTP-клиентом, а также он не использует собственные обработчики. Я использую Modern Http Client быстрее. –

ответ

1

Есть сообщения об ошибках, этот точный вопрос:
https://bugzilla.xamarin.com/show_bug.cgi?id=21477

Эта ошибка помеченных как ПОСТАНОВИЛИ FIXED и порекомендован действие для обновления до последней стабильной сборки. Но есть и другие (новые) багрепортов, которые указывают на то же самое, что по-прежнему открыты, например:
https://bugzilla.xamarin.com/show_bug.cgi?id=34747

Я сделал обходной путь реализации моей HttpHandler так:

 
     public class DecompressionHttpClientHandler : HttpClientHandler 
     { 
      protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
      { 
       request.Headers.AcceptEncoding.Add(new System.Net.Http.Headers.StringWithQualityHeaderValue("gzip")); 
       var msg = await base.SendAsync(request, cancellationToken); 
       if (msg.Content.Headers.ContentEncoding.Contains("gzip")) 
       { 
        var compressedStream = await msg.Content.ReadAsStreamAsync(); 
        var uncompresedStream = new System.IO.Compression.GZipStream(compressedStream, System.IO.Compression.CompressionMode.Decompress); 
        msg.Content = new StreamContent(uncompresedStream); 
       } 
       return msg; 
      } 
     } 

Обратите внимание, что код выше - всего лишь пример, а не окончательное решение. Например, запрос не будет сжат, и все заголовки будут удалены из результата. Но ты получил идею.

Смежные вопросы