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
方法):

  • 如果它被取消(
    IsCancellationRequested
    为true),则表示请求确实被取消
  • 如果没有,则表示请求超时
当然,这不是很方便……如果超时,最好接收
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
更高。有必要区分超时取消和用户取消。其结果是您可能无法得到de>WebException在您的
AggregateException
中。正如其他人所说,您必须假设TaskCanceledException是超时。我正在使用try{//code here}catch(AggregateException异常){if(exception.InnerExceptions.OfType().Any()){//此处句柄超时}我对此进行了测试,并且
GetStreamAsync
为我抛出了一个
TaskCanceledException
。我如何判断
TaskCanceledException
是否是由HTTP超时引起的,比如说直接取消或其他原因?@UserControl check
TaskCanceledException.CancellationToken.IsCancellationRequested
。如果为false,则可以解释原因可以肯定这是一个超时。事实证明,你不能指望在直接取消时设置异常的令牌,正如我之前所想:@测试它们的行为没有什么不同。只是你有一个令牌代表用户取消请求和一个内部令牌(您无法访问并且不需要)这表示客户端超时。这是与我的经验不同的用例。在任何情况下都无法捕获WebException。其他人是否有不同的体验?@crush
WebException
。可能会有所帮助。如果我不使用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)};