HttpClient取消不会杀死底层TCP调用

时间:2017-08-07 07:50:02

标签: c# dotnet-httpclient cancellationtokensource cancellation-token

我试图将HttpClient调用的默认超时设置为5秒。

我已通过CancellationTokenSource完成此操作。

这里是相关的代码:

var cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(TimeSpan.FromSeconds(5));
var result = _httpClient.SendAsync(request, cancellationToken.Token);

正如我预期的那样,调用代码获得"任务被取消"错误(我在.NET 4.7控制台应用程序中测试过),但我注意到在Fiddler中请求仍然运行了1分钟,直到它最终放弃:

enter image description here

有人可以解释这种行为吗?

我希望在触发取消时基础请求也会被取消。

_httpClient实例化为:new HttpClient { BaseAddress = baseAddress }

我知道有Timeout设置,但不确定我是否应该使用该设置或取消令牌?我的猜测Timeout是非异步/等待情况吗?

2 个答案:

答案 0 :(得分:2)

正如Damien在评论中所说,HttpClient尽可能多地重新使用连接,因此取消时关闭的原因就不再是。

取消这样的请求时,HttpClient将停止向/从另一端发送/接收数据。它不会发送任何信息通知另一方它被取消了。因此,您看到的1分钟超时取决于连接另一端的行为。

此外,如果您想在5秒后取消每个请求,也可以将Timeout的{​​{1}}属性设置为_httpClient。行为将完全相同(如果另一端在5秒内没有响应,则会抛出TimeSpan.FromSeconds(5)。)

答案 1 :(得分:0)

如果有人感兴趣,您可以尝试以下方法来根据HttpClient请求应用自己的超时。它似乎对我有用,将SendAsync()限制为2秒,并在发生超时时立即返回:

private async Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, 
    TimeSpan? timeout = null)
{
    if (timeout == null)
        return await _httpClient.SendAsync(request);
    else
    {
        using (var cts = new CancellationTokenSource(timeout.Value))
        {
            var sendTask = _httpClient.SendAsync(request);
            while (true)
            {
                if (sendTask.IsCompleted)
                    break;
                else
                {
                    cts.Token.ThrowIfCancellationRequested();
                    Thread.Sleep(10);
                }
            }
            return await sendTask;
        }
    }
}