我怎么知道HttpClient何时超时?

Ben*_*jol 123 c# timeout dotnet-httpclient

据我所知,没有办法知道它特别是发生了超时.我不是在寻找合适的地方,还是我错过了更大的东西?

string baseAddress = "http://localhost:8080/";
var client = new HttpClient() 
{ 
    BaseAddress = new Uri(baseAddress), 
    Timeout = TimeSpan.FromMilliseconds(1) 
};
try
{
    var s = client.GetAsync("").Result;
}
catch(Exception e)
{
    Console.WriteLine(e.Message);
    Console.WriteLine(e.InnerException.Message);
}
Run Code Online (Sandbox Code Playgroud)

返回:

发生了一个或多个错误.

任务被取消了.

mur*_*eus 57

您需要等待该GetAsync方法.TaskCanceledException如果它已超时,它将抛出一个.此外,GetStringAsync并在GetStreamAsync内部处理超时,所以他们永远不会抛出.

string baseAddress = "http://localhost:8080/";
var client = new HttpClient() 
{ 
    BaseAddress = new Uri(baseAddress), 
    Timeout = TimeSpan.FromMilliseconds(1) 
};
try
{
    var s = await client.GetAsync();
}
catch(Exception e)
{
    Console.WriteLine(e.Message);
    Console.WriteLine(e.InnerException.Message);
}
Run Code Online (Sandbox Code Playgroud)

  • 如何判断`TaskCanceledException`是否由HTTP超时引起,而不是直接取消或其他原因? (35认同)
  • @UserControl检查`TaskCanceledException.CancellationToken.IsCancellationRequested`.如果为false,您可以合理地确定它是超时. (8认同)
  • 我对此进行了测试,并且`GetStreamAsync`为我抛出了一个`TaskCanceledException`. (2认同)
  • 事实证明,您不能指望`IsCancellationRequested`在直接取消时在异常令牌上进行设置,就像我以前认为的那样:http://stackoverflow.com/q/29319086/62600 (2认同)
  • @testing他们的行为不同*.只是你有一个代表用户取消请求的令牌和一个代表客户端超时的内部(你不能访问而你不需要).不同的是用例 (2认同)

vez*_*kov 54

我正在复制同样的问题,这真的很烦人.我发现这些有用:

HttpClient - 处理聚合异常

HttpClient.GetAsync中的错误应该抛出WebException,而不是TaskCanceledException

一些代码以防链接无处可寻:

var c = new HttpClient();
c.Timeout = TimeSpan.FromMilliseconds(10);
var cts = new CancellationTokenSource();
try
{
    var x = await c.GetAsync("http://linqpad.net", cts.Token);  
}
catch(WebException ex)
{
    // handle web exception
}
catch(TaskCanceledException ex)
{
    if(ex.CancellationToken == cts.Token)
    {
        // a real cancellation, triggered by the caller
    }
    else
    {
        // a web request timeout (possibly other things!?)
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 22

我发现确定服务调用是否超时的最佳方法是使用取消令牌而不是HttpClient的超时属性:

var cts = new CancellationTokenSource();
cts.CancelAfter(timeout);
Run Code Online (Sandbox Code Playgroud)

然后在服务调用期间处理CancellationException ...

catch(TaskCanceledException)
{
    if(!cts.Token.IsCancellationRequested)
    {
        // Timed Out
    }
    else
    {
        // Cancelled for some other reason
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,如果超时发生在服务端,那么应该能够通过WebException来处理.

  • 嗯,我想应该删除否定运算符(在编辑中添加)才能使该示例有意义?如果“cts.Token.IsCancellationRequested”为“true”,则一定意味着发生了超时? (3认同)

Kne*_*lis 22

从 .NET 5 开始,实现已经改变HttpClient仍然抛出 a TaskCanceledException,但现在将 a 包装TimeoutExceptionInnerException。因此,您可以轻松检查请求是否已取消或超时(从链接的博客文章中复制的代码示例):

try
{
    using var response = await _client.GetAsync("http://localhost:5001/sleepFor?seconds=100");
}
// Filter by InnerException.
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
    // Handle timeout.
    Console.WriteLine("Timed out: "+ ex.Message);
}
catch (TaskCanceledException ex)
{
    // Handle cancellation.
    Console.WriteLine("Canceled: " + ex.Message);   
}
Run Code Online (Sandbox Code Playgroud)


use*_*702 8

来自http://msdn.microsoft.com/en-us/library/system.net.http.httpclient.timeout.aspx

域名系统(DNS)查询最多可能需要15秒才能返回或超时.如果您的请求包含需要解析的主机名,并且您将Timeout设置为小于15秒的值,则在抛出WebException之前可能需要15秒或更长时间才能指示请求超时.

然后,您可以访问该Status属性,请参阅WebExceptionStatus

  • 如果等待时间超过任务的超时时间,您将得到一个`TaskCanceledException`.这似乎是由TPL的内部超时处理抛出的,其处理级别高于`HttpWebClient`.[似乎没有一个好方法](http://stackoverflow.com/questions/12666922/httpclient-distinguish-timeout-from-user-cancellation)来区分超时取消和用户取消.这样做的结果是你可能在`AggregateException`中没有得到`WebException`. (5认同)
  • 嗯,我回来了一个带有`TaskCancelledException`的`AggregateException`.我一定做错了什么... (3认同)

Tho*_*que 5

基本上,您需要捕获OperationCanceledException并检查传递给的取消令牌的状态SendAsync(或者GetAsync,或者HttpClient您正在使用的任何方法):

  • 如果它被取消(IsCancellationRequested是真的),这意味着请求确实被取消了
  • 如果不是,则表示请求超时

当然,这不是很方便...... TimeoutException如果超时,最好收到一个.我在这里提出了一个基于自定义HTTP消息处理程序的解决方案:使用HttpClient更好地处理超时