设置C# HttpClient请求超时时间,无论主机/服务器是否可用

4
我正在处理httpclient和超时配置问题。经过大量的谷歌搜索,我得出以下结论:
  • 只有当我连接到一个可用的主机/服务器后,Http客户端超时才有效。
  • 如果主机不可用或服务器已关闭,则HttpClient.Timeout无效,并且在约80秒后,我会得到一个包含SocketException(连接被拒绝)的TaskCancelledException。

我了解到httpClient超时仅在服务器接收请求后才起作用,因此,如果主机/服务器不可用,我会遇到与套接字相关的长时间超时。

我需要为我的httpClient getAsync、postAsync等请求配置更广泛的超时,并在指定的时间内停止操作,无论服务器是否可用。

我无法想象如何有效地控制超时时间,那个stackoverflow线程(link)建议在这种情况下采用任务取消方法:

var timeout = Task.Delay(10000); // 10 seconds timeout
var request = httpClient.GetAsync("http://www.google.com");

await Task.WhenAny(timeout, request); // wait for either timeout or the request

if (timeout.IsCompleted) // if the timeout ended first, then handle it
{
    // handle timeout
}

// otherwise continue processing the request result
var response = await request;

虽然这可能有效,但我将失去套接字异常并且控制力较差。简而言之,我试图找到一种方法来设置解析/连接服务器的超时时间(约2秒),以及等待一旦与服务器建立连接后响应的更高超时时间。
对我来说这是有意义的,因为我的Web服务器是通过本地网络访问的,所以2秒已经足够得出“服务器不可用”的结论,但一旦服务器开始处理响应,我需要更长的等待响应超时时间。
提前致谢。
3个回答

1

那个stackoverflow的帖子...,建议任务取消方法

链接的问题解决方法是正确的。

基本上,问题在于连接超时由操作系统设置管理,无法直接在代码中设置。

虽然这可能有效,但我会失去套接字异常并且控制不佳

捕获和记录套接字异常(或任何其他异常)没有问题。只需为“主”任务设置适当的任务取消即可:

// task is returned from async method performing payload, e.g. httpClient.GetAsync
task.ContinueWith(
    t =>
    {
        var exception = t.Exception;

        // do what you want here
    },
    TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);

我会尝试一下,但是提前说一下,我认为这与我的目标无关,就像问题描述的那样:“简而言之,我试图找到一种设置解析/连接服务器的超时时间(约2秒)以及在连接建立后等待响应的更高超时时间的方法。” - Fran CD
@FranCD:是的,你不能设置它。所以,唯一的方法就是"忘记"长时间运行的连接尝试。 - Dennis
真的很烦人,应该有一种方法来正确控制不同的超时时间,因为2秒钟足以确定服务器是否可用,但对于等待某些请求结果可能太少了。我会发布一个解决方法的答案(我今天会尝试它),你觉得那个想法怎么样? - Fran CD

0

我在考虑这个变通的方法:

启动两个并行的HTTP请求,其中一个是一个虚拟的GET请求(服务器直接响应OK),我将使用问题中推荐的方法等待这个任务2秒钟。另一个请求是“真实请求”...如果第一个请求在两秒内没有完成,我也会取消第二个请求,但如果第一个请求正常结束,那么服务器就正常工作了,我会依赖于httpClient.Timeout来处理第二个请求。

是的,对服务器来说这是一种额外负担,因为每个请求都变成了两个请求,但我的服务器是局域网,每分钟只有5-10个客户端进行1-2个请求,所以我会考虑这种方法。或者也许这是个糟糕的主意...你觉得呢?


-1

由于GetAsync返回Task,因此您可以使用Task.Wait Method

例如:

var readTask = httpClient.GetAsync("http://www.google.com");

if (readTask.Wait(2 * 1000))
{
    // Return Result if exec dosn't take more than 2 sec
    // return await readTask;
    return readTask.Result;
}
else
{
    // Fail to complete exec in 2 sec
    return string.Empty;
}

1
我会尝试一下,但是提前说一下,我认为这与我的目标无关,就像问题描述的那样:“简而言之,我试图找到一种方法来设置解析/连接服务器的超时时间(约2秒),以及在连接建立后等待响应的更高超时时间。” - Fran CD
1
@FranCD:不要用这种方式等待异步任务。这段代码1)阻塞调用线程;2)导致死锁。像你链接的问题中那样以异步方式执行。 - Dennis
我在这里只是解释一下等待方法,并且我参考了MSDN链接来了解它的工作原理。 - CorrM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接