.net 是否重新使用HttpClient,但每个请求的超时设置不同?

.net 是否重新使用HttpClient,但每个请求的超时设置不同?,.net,dotnet-httpclient,.net,Dotnet Httpclient,为了使用HttpClient重用打开的TCP连接,您必须为所有请求共享一个实例 这意味着我们不能简单地用不同的设置(例如超时或头)实例化HttpClient 我们如何共享连接并同时使用不同的设置?这是非常容易的,事实上是默认的,使用较旧的HttpWebRequest和WebClient基础结构 请注意,在发出请求之前简单地设置HttpClient.Timeout不是线程安全的,在并发应用程序(例如ASP.NET网站)中不起作用。在后台,HttpClient只使用取消令牌来实现超时行为。如果要根据

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

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

我们如何共享连接并同时使用不同的设置?这是非常容易的,事实上是默认的,使用较旧的
HttpWebRequest
WebClient
基础结构


请注意,在发出请求之前简单地设置
HttpClient.Timeout
不是线程安全的,在并发应用程序(例如ASP.NET网站)中不起作用。

在后台,
HttpClient
只使用取消令牌来实现超时行为。如果要根据请求更改,可以直接执行相同操作:

using var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(30));
await httpClient.GetAsync("http://www.google.com", cts.Token);
请注意,
HttpClient
的默认超时为100秒,即使在请求级别设置了更高的值,请求仍将在该点取消。要解决此问题,请在
HttpClient
上设置一个“max”超时,该超时可以是无限的:

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

被接受的答案很好,但我想为将来寻找这个答案的人提供另一个场景。在我的例子中,我已经在使用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;
        }
    }
}
公共异步静态任务SendRequest(CancellationToken CancellationToken)
{
var ctsForTimeout=新的CancellationTokenSource();
ctsForTimeout.CancelAfter(时间跨度从秒开始(5));
var cancellationTokenForTimeout=ctsForTimeout.Token;
使用(var linkedts=cancelationtokensource.CreateLinkedTokenSource(取消令牌,取消令牌FortimeOut))
{
尝试
{
返回等待httpClient.GetAsync(“http://asdfadsf“,linkedts.Token);
}
抓住
{
//只是为了举例说明
if(cancellationTokenForTimeout.IsCancellationRequested)
{
控制台写入线(“超时”);
}
else if(cancellationToken.IsCancellationRequested)
{
Console.WriteLine(“其他取消令牌已取消”);
}
投掷;
}
}
}

除了
超时
之外,您希望在同一实例上更改哪些设置?每个请求都可以设置头,改变
BaseAddress
没有多大意义,因为每个不同的头都需要一个新的连接。实际上,
Timeout
可能是您希望在同一实例上改变的唯一属性。如果回答了这个问题,我可以向您展示如何对每个请求使用不同的超时。@ToddMenier这是一个很好的观点。这将回答这个问题,是的!需要澄清的是,重用
HttpClient
意味着您正在重用单个TCP连接。这里没有“池”的概念。@ToddMenier我很确定那不是真的。这也意味着在同一HttpClient对象上的并行请求不会并行执行,我很确定情况并非如此。正如在另一个答案中提到的,这只能减少取消时间。因此,如果您计划使用此方法,最好将默认超时设置为无限(或其他您满意的数量),并计划为每个请求提供您自己的取消令牌。@Todd Menier:我按照您的答案回答了一个类似的问题,但我无法解决它,也许您可以帮助我: