重新使用 HttpClient 但每个请求的超时设置不同?

问题描述 投票:0回答:4

为了重用

HttpClient
打开的 TCP 连接,您必须为所有请求共享一个实例。

这意味着我们不能简单地用不同的设置(例如超时或标题)实例化

HttpClient

我们如何共享连接并同时使用不同的设置?这非常简单,实际上是默认设置,使用较旧的

HttpWebRequest
WebClient
基础设施。

请注意,在发出请求之前简单地设置

HttpClient.Timeout
不是线程安全的,并且不会在并发应用程序(例如 ASP.NET 网站)中工作。

.net dotnet-httpclient
4个回答
97
投票

在幕后,

HttpClient
只是使用取消标记来实现超时行为。如果你想根据请求改变它,你可以直接做同样的事情:

using var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(30));
await httpClient.GetAsync("http://www.google.com", cts.Token);

请注意,

HttpClient
的默认超时时间为 100 秒,即使您在请求级别设置了更高的值,该请求仍会在该时间点被取消。要解决这个问题,请在
HttpClient
上设置一个“最大”超时,它可以是无限的:

httpClient.Timeout = System.Threading.Timeout.InfiniteTimeSpan;

10
投票

接受的答案很好,但我想为将来寻找这个的人提供另一个场景。在我的例子中,我已经在使用 CancellationTokenSource,它会在用户选择取消时取消其令牌。因此,在那种情况下,您仍然可以通过使用 CancellationTokenSource 的 CreateLinkedTokenSource 方法来使用此技术。因此,在我的场景中,http 操作将因超时或用户干预而取消。这是一个示例:

public async static Task<HttpResponseMessage> SendRequest(CancellationToken cancellationToken)
{
    var ctsForTimeout = new CancellationTokenSource();
    ctsForTimeout.CancelAfter(TimeSpan.FromSeconds(5));
    var cancellationTokenForTimeout = ctsForTimeout.Token;

    using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cancellationTokenForTimeout))
    {
        try
        {
            return await httpClient.GetAsync("http://asdfadsf", linkedCts.Token);
        }
        catch
        {
            //just for illustration purposes
            if (cancellationTokenForTimeout.IsCancellationRequested)
            {
                Console.WriteLine("timeout");
            }
            else if (cancellationToken.IsCancellationRequested)
            {
                Console.WriteLine("other cancellation token cancelled");
            }
            throw;
        }
    }
}

0
投票

如果您已经在使用

CancellationToken
可能来自异步 API 端点,您可以使用
CancellationToken
将它与另一个
CancellationTokenSource.CreateLinkedTokenSource
结合。

举个例子:

public async Task<HttpResponseMessage> SendRequestWithTimeout(HttpRequestMessage request, Timespan timeout, CancellationToken ct){
    var timeoutCt = new CancellationTokenSource(timeout).Token;
    var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(ct, timeoutCt).Token;
    return await httpClient.SendAsync(request, linkedCts);
}


0
投票

.NET 6(及更高版本)现在包含您可以使用的

Task.WaitAsync(TimeSpan)
方法。

    await httpClient.SendAsync(request).WaitAsync(TomeSpan.FromSeconds(5));

获取将在该任务完成或 指定超时到期。

https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.waitasync?view=net-8.0#system-threading-tasks-task-waitasync(system-timespan)

© www.soinside.com 2019 - 2024. All rights reserved.