如何知道HttpClient何时超时?


142

据我所知,没有办法知道具体是发生了超时。我是不是在正确的地方寻找东西,还是缺少更大的东西?

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);
}

返回:

发生一个或多个错误。

任务已取消。


3
我们可以在GitHub上解决此问题:HttpClient在超时#20296上抛出TaskCanceledException
csrowell

这个问题的巨大支持。另外...知道如何在UWP上执行此操作吗?它的Windows.Web.HTTP.HTTPClient没有超时成员。此外,GetAsync方法不接受取消令牌...
新做的事,

1
6年后,似乎仍然无法知道客户是否超时。
史蒂夫·史密斯

Answers:


61

您需要等待该GetAsync方法。TaskCanceledException如果超时,它将抛出一个。此外,GetStringAsyncGetStreamAsync内部处理超时,所以他们不会抛出。

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);
}

2
我对此进行了测试,并为我GetStreamAsync扔了一个TaskCanceledException
山姆

38
如何判断是否TaskCanceledException是HTTP超时引起的,而不是直接取消或其他原因引起的?
UserControl 2014年

8
@UserControl检查TaskCanceledException.CancellationToken.IsCancellationRequested。如果为false,则可以合理确定这是超时。
Todd Menier 2014年

3
事实证明,您不能指望IsCancellationRequested像我以前认为的那样在直接取消时在异常令牌上进行设置:stackoverflow.com/q/29319086/62600
Todd Menier

2
@testing他们不表现不同。只是您有一个代表用户取消请求的令牌和一个代表客户端超时的内部令牌(您无法访问并且不需要)。这是不同的用例
Rufo爵士,

59

我正在重现同样的问题,这确实很烦人。我发现这些有用:

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!?)
    }
}

以我的经验,在任何情况下都不会陷入WebException。其他人有不同的经历吗?
暗恋

1
WebException 可以抓到@crush 。也许会有所帮助。
DavidRR

如果我不使用cts,这对我不起作用。我只使用Task <T> task = SomeTask()试试{T结果= task.Result} catch(TaskCanceledException){} catch(Exception e){}仅捕获一般异常,而不捕获TaskCanceledException。我的代码版本有什么问题?
Naomi

1
我创建了一个新的错误报告,因为原始错误报告似乎出现在存档的论坛帖子中:connect.microsoft.com/VisualStudio/feedback/details/3141135
StriplingWarrior

1
如果令牌是从外部传递的,请default(CancellationToken)在与进行比较之前进行检查ex.CancellationToken
SerG

25

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

var cts = new CancellationTokenSource();
cts.CancelAfter(timeout);

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

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

当然,如果超时发生在事物的服务端,那应该可以由WebException处理。


1
嗯,我想应该删除否定运算符(在编辑中添加了),以使该示例有意义?如果cts.Token.IsCancellationRequestedtrue就一定意味着超时已发生?
Lasse Christiansen,

9

http://msdn.microsoft.com/zh-cn/library/system.net.http.httpclient.timeout.aspx

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

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


3
嗯,我又回到了AggregateException同一个TaskCancelledException内。我一定做错了什么…
Benjol

您正在使用catch(WebException e)吗?
user247702

不,如果我尝试,将AggregateException无法处理。如果创建VS控制台项目,则添加的引用System.Net.Http并将代码放入main,您可以自己查看(如果需要)。
Benjol

5
如果等待时间超过任务的超时时间,您将得到一个TaskCanceledException。TPL的内部超时处理似乎在比更高的级别上抛出了该错误HttpWebClient。这里似乎不是一个好办法超时取消和用户取消区分。这样做的结果是,你可能不会得到WebException你内AggregateException
JT。

1
正如其他人所说,您必须假设TaskCanceledException是超时。我正在使用try {// //代码在这里} catch(AggregateException异常){if(exception.InnerExceptions.OfType <TaskCanceledException>()。Any()){//这里处理超时}}
Vdex

8

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

  • 如果已取消(IsCancellationRequested是),则表示请求实际上已取消
  • 如果不是,则表示请求超时

当然,这不是很方便...最好TimeoutException在超时的情况下接收。我在这里提出基于自定义HTTP消息处理程序的解决方案:使用HttpClient更好地处理超时


啊!是你!我今天早些时候在您的博客中发表了评论。但是对于这个答案,我认为您对IsCancellationRequested的观点是不正确的,因为当我自己没有取消它时,这似乎对我来说一直是正确的
knocte

@knocte太奇怪了...但是在那种情况下,我的博客文章中的解决方案对您没有帮助,因为它也依赖于此
Thomas Levesque

1
在有关此问题的github问题中,许多人声称我所说的话:IsCancellationRequested在超时时为true;因此,我很
乐意拒绝

@knocte,我不知道该告诉您什么。。。我已经使用了很长时间了,它一直对我有用。您是否设置HttpClient.Timeout为无穷大?
托马斯·列维斯克

不,我没有,因为我自己无法控制HttpClient,这是我正在使用的第三方库,也是使用它的库
knocte19年

-1
_httpClient = new HttpClient(handler) {Timeout = TimeSpan.FromSeconds(5)};

这是我通常所做的,对我来说似乎很不错,尤其是在使用代理时。


1
这是设置httpclient超时的方式。这不能解决问题,即如何确定httpclient何时超时。
伊桑·菲舍尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.