C# 如何判断 HttpClient 何时超时?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10547895/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 14:15:28  来源:igfitidea点击:

How can I tell when HttpClient has timed out?

c#timeoutdotnet-httpclient

提问by Benjol

As far as I can tell, there's no way to know that it's specifically a timeout that has occurred. Am I not looking in the right place, or am I missing something bigger?

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

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

This returns:

这将返回:

One or more errors occurred.

A task was canceled.

发生了一个或多个错误。

一个任务被取消。

回答by user247702

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

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

A Domain Name System (DNS) query may take up to 15 seconds to return or time out. If your request contains a host name that requires resolution and you set Timeout to a value less than 15 seconds, it may take 15 seconds or more before a WebException is thrown to indicate a timeout on your request.

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

You then get access to the Statusproperty, see WebExceptionStatus

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

回答by murkaeus

You need to await the GetAsyncmethod. It will then throw a TaskCanceledExceptionif it has timed out. Additionally, GetStringAsyncand GetStreamAsyncinternally handle timeout, so they will NEVER throw.

您需要等待该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);
}

回答by vezenkov

I am reproducing the same issue and it's really annoying. I've found these useful:

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

HttpClient - dealing with aggregate exceptions

HttpClient - 处理聚合异常

Bug in HttpClient.GetAsync should throw WebException, not TaskCanceledException

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

Some code in case the links go nowhere:

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

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

回答by Hyman

I found that the best way to determine if the service call has timed out is to use a cancellation token and not the HttpClient's timeout property:

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

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

And then handle the CancellationException during the service call...

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

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

Of course if the timeout occurs on the service side of things, that should be able to handled by a WebException.

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

回答by Thomas Levesque

Basically, you need to catch the OperationCanceledExceptionand check the state of the cancellation token that was passed to SendAsync(or GetAsync, or whatever HttpClientmethod you're using):

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

  • if it was canceled (IsCancellationRequestedis true), it means the request really was canceled
  • if not, it means the request timed out
  • 如果它被取消(IsCancellationRequested为真),则表示请求确实被取消了
  • 如果没有,则表示请求超时

Of course, this isn't very convenient... it would be better to receive a TimeoutExceptionin case of timeout. I propose a solution here based on a custom HTTP message handler: Better timeout handling with HttpClient

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

回答by Syv Development

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

is what I usually do, seems to work out pretty good for me, its especially good when using proxies.

这是我通常做的,似乎对我来说效果很好,在使用代理时特别好。