Xamarin HTTP 请求超时
Timeouts in Xamarin HTTP requests
晚上好!
我试图 clean/refine 一些代码并最终发现 Xamarin HTTP 请求 超时问题 (如我的原始线程中所述:Async Download and Deserialize ).
发现问题(仅使用 Xamarin.Android 测试;不知道 iOS):
当无法访问 主机时 (例如,脱机的本地服务器),GetAsync
在大约 3 之后抛出 System.Net.WebException
分钟 ,消息 错误: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;
}
}
调用方式:
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);
}
}
设置client.Timeout
好像不行。
不管怎样,cancellationToken 不应该在 10 秒后自动取消吗?
此超时问题发生在:
- 一个offline/unreachable IP地址(在我的例子中是离线本地服务器
例如 192.168.1.101:8080)被请求(即使用
GetAsync
、SendAsync
、
GetResponseAsync
)
代码在以下情况下运行良好:
- 请求来自 桌面客户端(例如,WPF)。如果
IP 是 offline/unreachable 它非常快地抛出 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)
(及以上)- 不是
工作
有什么想法吗?谢谢!
我发现更改 Android 的 http 客户端设置解决了我的问题。
解决问题:
- 从
HttpClient
实施到 AndroidClientHandler
- 从 SSL/TLS 实现到 Native TLS 1.2+
在 Xamarin Android 项目选项中。 "Default" 值使用了导致问题的 Mono 自己的客户端。
我发布了更多详细信息 here。
晚上好!
我试图 clean/refine 一些代码并最终发现 Xamarin HTTP 请求 超时问题 (如我的原始线程中所述:Async Download and Deserialize ).
发现问题(仅使用 Xamarin.Android 测试;不知道 iOS):
当无法访问 主机时 (例如,脱机的本地服务器),GetAsync
在大约 3 之后抛出 System.Net.WebException
分钟 ,消息 错误: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;
}
}
调用方式:
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);
}
}
设置client.Timeout
好像不行。
不管怎样,cancellationToken 不应该在 10 秒后自动取消吗?
此超时问题发生在:
- 一个offline/unreachable IP地址(在我的例子中是离线本地服务器
例如 192.168.1.101:8080)被请求(即使用
GetAsync
、SendAsync
、GetResponseAsync
)
代码在以下情况下运行良好:
- 请求来自 桌面客户端(例如,WPF)。如果 IP 是 offline/unreachable 它非常快地抛出 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)
(及以上)- 不是 工作
有什么想法吗?谢谢!
我发现更改 Android 的 http 客户端设置解决了我的问题。
解决问题:
- 从
HttpClient
实施到AndroidClientHandler
- 从 SSL/TLS 实现到 Native TLS 1.2+
在 Xamarin Android 项目选项中。 "Default" 值使用了导致问题的 Mono 自己的客户端。
我发布了更多详细信息 here。