Xamarin HTTP请求超时

Api*_*oud 7 c# asynchronous http xamarin.android

晚上好!

我试图清理/细化一些代码,最终找到有问题的Xamarin HTTP请求超时(在我原来的线程描述:异步下载和反序列化).

发现问题(仅使用Xamarin.Android进行测试;不了解iOS):

当一个主机无法到达(例如,离线本地服务器),GetAsync将引发System.Net.WebException后大致3分钟与消息错误:ConnectFailure(连接超时).内部异常是System.Net.Sockets.SocketsException(完整日志:http://pastebin.com/MzHyp2FM).

码:

internal static class WebUtilities
{
    /// <summary>
    /// Downloads the page of the given url
    /// </summary>
    /// <param name="url">url to download the page from</param>
    /// <param name="cancellationToken">token to cancel the download</param>
    /// <returns>the page content or null when impossible</returns>
    internal static async Task<string> DownloadStringAsync(string url, CancellationToken cancellationToken)
    {
        try
        {
            // create Http Client and dispose of it even if exceptions are thrown (same as using finally statement)
            using (var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(5) })
            {
                // should I always do this?
                client.CancelPendingRequests();

                // Issue here; Timeout of roughly 3 minutes
                using (var response = await client.GetAsync(url, cancellationToken).ConfigureAwait(false))
                {
                    // if response was successful (otherwise return null)
                    if (response.IsSuccessStatusCode)
                    {
                        // return its content
                        return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    }
                }
            }
        }
        // TODO: split exceptions?
        catch (Exception ex) when (ex is System.Net.Sockets.SocketException ||
                                    ex is InvalidOperationException ||
                                    ex is OperationCanceledException ||
                                    ex is System.Net.Http.HttpRequestException)
        {
            WriteLine("DownloadStringAsync task has been cancelled.");
            WriteLine(ex.Message);
            return null;
        }

        // return null if response was unsuccessful
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

通话方式:

internal static async Task CallAsync(string url)
    {
        using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
        {
            var token = cts.Token;
            token.ThrowIfCancellationRequested();

            string result = await WebUtilities.DownloadStringAsync(url, token).ConfigureAwait(false);
        }
    }
Run Code Online (Sandbox Code Playgroud)

设置client.Timeout似乎不起作用.

无论哪种方式,10秒后不应该取消自动取消

此超时问题发生在:

  • 离线/不可达的IP地址(在我的情况下离线本地服务器如192.168.1.101:8080)的要求(即,使用GetAsync,SendAsync, GetResponseAsync)

代码适用于:

  • 该请求来自桌面客户端(例如,WPF).如果IP处于脱机/无法访问状态,它会非常快速地抛出4个异常(无法建立连接,因为目标计算机主动拒绝它).

结论

Xamarin似乎在Http请求中有一些错误(至少有超时?),因为它们没有给出预期的结果.从我读过的内容来看,它可能已经存在了几年(自2012年或2013年).

Xamarin单元测试也没有任何帮助:https://github.com/xamarin/xamarin-android/blob/1b3a76c6874853049e89bbc113b22bc632ed5ca4/src/Mono.Android/Test/Xamarin.Android.Net/HttpClientIntegrationTests.cs

编辑

  • Timeout = TimeSpan.FromMilliseconds(1000) - 工作
  • Timeout = Timeout = TimeSpan.FromSeconds(1) - 不起作用(?????)
  • Timeout = TimeSpan.FromMilliseconds(2000) (及以上) - 不起作用

有任何想法吗?谢谢!

PJe*_*ouf 3

我发现更改 Android 的 http 客户端设置解决了我的问题。
要解决这个问题:

  • HttpClient实施到AndroidClientHandler
  • SSL/TLS实施到本机 TLS 1.2+

在 Xamarin Android 项目选项中。“默认”值使用 Mono 自己的客户端,这导致了问题。

我在这里发布了更多详细信息。