C# 如何判断HttpClient何时超时?
据我所知,没有办法知道这是一个具体的超时已经发生。我是不是找错地方了,还是错过了更大的东西C# 如何判断HttpClient何时超时?,c#,timeout,dotnet-httpclient,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.
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);
}
这将返回:
发生了一个或多个错误
一项任务被取消
从
域名系统(DNS)查询最多可能需要15秒才能返回或超时。如果您的请求包含需要解析的主机名,并且您将Timeout设置为小于15秒的值,则可能需要15秒或更长时间才会引发WebException以指示请求超时
然后您可以访问
Status
属性,请参见您需要等待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);
}
我在复制同样的问题,这真的很烦人。我发现这些很有用: 一些代码,以防链接无处可用:
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!?)
}
}
我发现确定服务调用是否超时的最佳方法是使用取消令牌,而不是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处理。基本上,您需要捕获
OperationCanceledException
并检查传递给SendAsync
的取消令牌的状态(或GetAsync
,或您正在使用的任何HttpClient
方法):
- 如果它被取消(
为true),则表示请求确实被取消IsCancellationRequested
- 如果没有,则表示请求超时
TimeoutException
。我在这里提出了一个基于自定义HTTP消息处理程序的解决方案:
是我通常所做的,似乎对我来说很好,尤其是在使用代理时。从.NET 5开始,HttpClient
仍然抛出一个TaskCanceledException
,但现在将TimeoutException
包装为InnerException
。因此,您可以轻松地检查请求是否被取消或超时(代码示例复制自链接的博客帖子):
试试看
{
使用var response=wait_client.GetAsync(“http://localhost:5001/sleepFor?seconds=100");
}
//按InnerException筛选。
捕获(TaskCanceledException ex)时(ex.InnerException是TimeoutException)
{
//句柄超时。
Console.WriteLine(“超时:+ex.Message”);
}
捕获(TaskCanceledException ex)
{
//处理取消。
Console.WriteLine(“取消:+ex.Message”);
}
Hm,我得到了一个aggregateeexception
,里面有一个task cancelledeexception
。我一定是做错了什么……你在使用catch(WebException e)吗
?不,如果我尝试,则未处理aggregateeexception
。如果创建VS控制台项目,请添加对System.Net.Http
的引用,并将代码放入main
,您可以自己查看(如果愿意)。如果等待时间超过了任务的超时时间,您将得到一个TaskCanceledException
。这似乎是由TPL的内部超时处理抛出的,级别比HttpWebClient
更高。有必要区分超时取消和用户取消。其结果是您可能无法得到AggregateException
中。正如其他人所说,您必须假设TaskCanceledException是超时。我正在使用try{//code here}catch(AggregateException异常){if(exception.InnerExceptions.OfType().Any()){//此处句柄超时}我对此进行了测试,并且GetStreamAsync
为我抛出了一个TaskCanceledException
。我如何判断TaskCanceledException
是否是由HTTP超时引起的,比如说直接取消或其他原因?@UserControl checkTaskCanceledException.CancellationToken.IsCancellationRequested
。如果为false,则可以解释原因可以肯定这是一个超时。事实证明,你不能指望在直接取消时设置异常的令牌,正如我之前所想:@测试它们的行为没有什么不同。只是你有一个令牌代表用户取消请求和一个内部令牌(您无法访问并且不需要)这表示客户端超时。这是与我的经验不同的用例。在任何情况下都无法捕获WebException。其他人是否有不同的体验?@crushWebException
。可能会有所帮助。如果我不使用cts,这对我不起作用。我只是使用Task Task=SomeTask()试试{T result=task.result}catch(TaskCanceledException){}catch(Exception e){}只捕获一般异常,而不是TaskCanceledException。我的代码版本有什么问题?我创建了一个新的错误报告,因为原始错误报告似乎出现在存档的论坛帖子中:如果令牌是从外部传递的,请检查它不是默认值(取消令牌)
在与ex.CancellationToken
进行比较之前。我们可以在GitHub上对该问题进行投票:对该问题进行巨大的投票。另外…知道如何在UWP上进行此操作吗?它的Windows.Web.HTTP.HTTPClient没有超时成员。另外,GetAsync方法不接受取消令牌…6年后,似乎仍然不可能知道一个客户端超时..NET5最终实现了一个包装的TimeoutException
;请检查下面我的答案中的示例实现
_httpClient = new HttpClient(handler) {Timeout = TimeSpan.FromSeconds(5)};