176

据我所知,没有办法知道它具体是发生了超时。我没有找对地方,还是我错过了更大的东西?

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

这将返回:

发生一个或多个错误。

一个任务被取消了。

4

7 回答 7

74

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

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!?)
    }
}
于 2013-11-06T20:59:04.033 回答
65

您需要等待该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);
}
于 2012-10-15T18:10:31.293 回答
35

从 .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);   
}
于 2021-02-01T08:37:44.107 回答
29

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

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

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

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

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

于 2015-08-26T15:09:53.817 回答
11

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

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

当然,这不是很方便……如果TimeoutException超时,最好接收一个。我在这里提出了一个基于自定义 HTTP 消息处理程序的解决方案:Better timeout handling with HttpClient

于 2018-03-01T16:58:50.697 回答
10

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

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

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

于 2012-05-11T08:26:27.250 回答
-4
_httpClient = new HttpClient(handler) {Timeout = TimeSpan.FromSeconds(5)};

是我通常做的事情,似乎对我来说非常好,使用代理时尤其好。

于 2018-09-05T04:36:17.390 回答