【问题标题】:HttpClient seems to be ignoring the Timeout propertyHttpClient 似乎忽略了 Timeout 属性
【发布时间】:2019-09-11 13:07:25
【问题描述】:

我正在尝试通过在响应中返回 MultiPartContent 从服务器加载大量数据。但是,在 HttpGet 方法期间,我设置的超时值被忽略。我正在尝试设置更长的超时时间,因为在这种情况下等待是可以的。

我尝试了 10 分钟到 2 小时之间的各种超时值。实际上,用户第一次使用我们的应用程序时只需要等待约 5 分钟,而其他时间则更少。 我还尝试存储 HttpClient 的引用,以确保 api.HttpClient 不会每次都重新创建 HttpClient 对象。

var handler = new HttpClientHandler();
var progress = new ProgressMessageHandler(handler);
var api = APIHelpers.GetSession(progress);

progress.HttpReceiveProgress += (e, args) => ProgressChanged.Invoke(e, new SyncEventArgs(GlobalEnums.SyncStage.Downloading, args.ProgressPercentage * 0.01f));

api.HttpClient.Timeout = new TimeSpan(0, 10, 0);

var downloadUri = BuildURI();
var response = await api.HttpClient.GetAsync(downloadUri, HttpCompletionOption.ResponseHeadersRead);

我希望应用程序在抛出 Timeout 异常之前等待 10 分钟,但是在 100 秒后抛出异常(我相信这是默认值?)。 设置后检查HttpClient.Timeout 值确实表明它设置正确。

APIHelpers.GetSession() 方法返回我们 API 的一个对象,其中创建了授权标头。 HttpClient 对象可通过继承类访问。这是由 Swashbuckle 和 Swagger 创建的。我之前曾以这种方式成功使用过api.HttpClient.Timeout = x,所以我认为这不是问题所在。它似乎特别针对这种情况。

抛出的异常:

{System.Net.Http.HttpRequestException: An error occurred while sending the request ---> System.Net.WebException: The operation has timed out.
  at System.Net.HttpWebRequest.RunWithTimeoutWorker[T] (System.Threading.Tasks.Task`1[TResult] workerTask, System.Int32 timeout, System.Action abort, System.Func`1[TResult] aborted, System.Threading.CancellationTokenSource cts) [0x000f8] in <a1ab7fc4639d4d84af41d68234158b1c>:0 
  at System.Net.HttpWebRequest.EndGetResponse (System.IAsyncResult asyncResult) [0x00019] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.14.0.114/src/Xamarin.iOS/mcs/class/System/System.Net/HttpWebRequest.cs:1200 
  at System.Threading.Tasks.TaskFactory`1[TResult].FromAsyncCoreLogic (System.IAsyncResult iar, System.Func`2[T,TResult] endFunction, System.Action`1[T] endAction, System.Threading.Tasks.Task`1[TResult] promise, System.Boolean requiresSynchronization) [0x0000f] in <939d99b14d934342858948926287beba>:0 
--- End of stack trace from previous location where exception was thrown ---

  at System.Net.Http.MonoWebRequestHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x003d1] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.14.0.114/src/Xamarin.iOS/mcs/class/System.Net.Http/MonoWebRequestHandler.cs:499 
   --- End of inner exception stack trace ---
  at System.Net.Http.MonoWebRequestHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x0046a] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.14.0.114/src/Xamarin.iOS/mcs/class/System.Net.Http/MonoWebRequestHandler.cs:503 
  at Microsoft.Rest.RetryDelegatingHandler+<>c__DisplayClass11_0.<SendAsync>b__1 () [0x000ad] in <6a6c837cafbb4f1faffaba1ff30ca4e3>:0 
  at Microsoft.Rest.RetryDelegatingHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x00150] in <6a6c837cafbb4f1faffaba1ff30ca4e3>:0 
  at System.Net.Http.Handlers.ProgressMessageHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x00087] in <19af20e76ce04547b3fc150a0f8f2d47>:0 
  at System.Net.Http.HttpClient.SendAsyncWorker (System.Net.Http.HttpRequestMessage request, System.Net.Http.HttpCompletionOption completionOption, System.Threading.CancellationToken cancellationToken) [0x0009e] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.14.0.114/src/Xamarin.iOS/mcs/class/System.Net.Http/System.Net.Http/HttpClient.cs:281 
  at ...

编辑: 我只是添加了一些我尝试过的其他东西来解决这个问题。

  1. 我尝试使用 Xamarin.Forms 中的 DependencyService 来获取每个平台的本机 HttpClientHandlersHttpClient 对象,我可以在其中设置每个平台的超时时间,而不是依靠 Xamarin.Forms 为我翻译它。这具有完全相同的结果。
public HttpMessageHandler GetHttpHandler(double timeoutSeconds)
{
    var sessionConfig = NSUrlSessionConfiguration.DefaultSessionConfiguration;
    sessionConfig.TimeoutIntervalForRequest = timeoutSeconds;
    sessionConfig.TimeoutIntervalForResource = timeoutSeconds;
    sessionConfig.WaitsForConnectivity = true;

    var sessionHandler = new NSUrlSessionHandler(sessionConfig);
    return sessionHandler;
}
  1. 我已经尝试为这个 API 调用创建一个新的 HttpClient 对象,但这里也没有运气。 (这将替换我代码中的 Apihelpers.GetSession()

【问题讨论】:

  • api.HttpClient 属性是如何定义的?是不是每次访问都会创建一个新的HttpClient
  • 另外,你说的是“超时异常”,但是当达到超时时HttpClient 会抛出一个TaskCancelledException。这是你看到的例外吗?
  • @GabrielLuci 我在原始帖子中写道,我已经尝试存储 HttpClient 对象以确保它不会每次都重新创建它并且不起作用。我已编辑我的帖子以包含例外情况
  • 哪个平台? iOS 还是|和 Android?
  • @SushiHangover iOS 和 Android 都有同样的问题。上述例外来自 iOS

标签: c# .net xamarin httpclient


【解决方案1】:

有一个known issue in both Xamarin.iOS and Xamarin.Android 忽略大于 100 秒的 HttpClient.Timeout 值。这是因为底层原生 http 客户端的超时设置为 100 秒,因此当 HttpClient.Timeout 值 > 100 秒时,此超时会在 .NET HttpClient 超时之前超时。这应该在所有最新的稳定版本中得到修复,因此请确保您已更新。如果您使用的是 Visual Studio 2017,则无法获得修复,您需要获取 VS 2019 才能获得修复。

【讨论】:

  • 谢谢,但我已经在使用最新版本的 Xamarin 和最新版本的 Visual Studio 2019!
  • 你会遇到服务器超时吗?如果服务器超时时间短于 HttpClient 超时时间,则 HttpClient 超时时间将永远不会触发更改。
  • 不是这样,因为当我只使用 new HttpClient() 时它工作正常并且 10 分钟的超时工作正常。如果我使用 new HttpClient(new ProgressHandler()) 那么它会忽略我的超时设置。问题似乎在于 ProgressHandler
【解决方案2】:

在我的 Xamarin Android 项目中遇到了同样的问题。通过在项目属性中将 HttpClient 实现更改为 Android 来解决它,如下所示:

【讨论】:

    猜你喜欢
    • 2015-12-11
    • 1970-01-01
    • 2015-05-28
    • 2012-08-09
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多