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

Posted

技术标签:

【中文标题】重新使用 HttpClient 但每个请求的超时设置不同?【英文标题】:Re-using HttpClient but with a different Timeout setting per request? 【发布时间】:2017-10-22 13:36:03 【问题描述】:

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

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

我们如何共享连接并同时使用不同的设置?这很简单,实际上是默认设置,使用较旧的 HttpWebRequestWebClient 基础架构。

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

【问题讨论】:

除了Timeout,您希望在同一实例上更改哪些设置?诸如标头之类的东西可以根据请求进行设置,而不同的BaseAddress 并没有多大意义,因为每个不同的都需要一个新的连接。实际上,Timeout 可能是您希望在同一实例上更改的 only 属性。如果可以回答问题,我可以向您展示如何为每个请求使用不同的超时。 @ToddMenier 这是一个很好的观点。这将回答这个问题,是的! 需要澄清的是,重用HttpClient 意味着您正在重用一个单个 TCP 连接。这里不涉及“池化”。 @ToddMenier 我很确定这不是真的。这也意味着对同一个 HttpClient 对象的并行请求不会并行执行,我很确定也不是这种情况。 【参考方案1】:

在后台,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;

【讨论】:

在另一个答案中提到,这只能减少取消的时间。因此,如果您打算使用此方法,最好将默认超时设置为无限(或您可以满意的其他数量),并计划为每个 每个 请求。 @Todd Menier:我按照你的回答解决了类似的问题,但我无法解决,也许你可以帮助我:***.com/questions/54326681/…【参考方案2】:

已接受的答案很好,但我想为将来寻找此问题的任何人提供另一种方案。就我而言,我已经在使用 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;
        
    

【讨论】:

以上是关于重新使用 HttpClient 但每个请求的超时设置不同?的主要内容,如果未能解决你的问题,请参考以下文章

android 用httpclient登录无法保持会话状态 最后两次请求的cookie都不一样!我明明设成一样了?

C# 中的 httpClient 调用超时,而 cUrl 正在工作

HttpClient 的请求超时

Httpclient在.net core3.1上成功运行,但更新到.net 5中连接超时(System.Net.Sockets.SocketException (10060)) C#

由于异步问题,并行 HttpClient 请求超时?

为什么C#HttpClient不能调用此URL(总是超时)?