AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79593567
Accepted
user25521292
user25521292
Asked: 2025-04-26 11:57:21 +0800 CST2025-04-26 11:57:21 +0800 CST 2025-04-26 11:57:21 +0800 CST

当我们已经有 PooledConnectionLifetime 时,为什么还要使用 .SetHandlerLifetime(...)

  • 772

假设我们有代码片段

builder.Services.AddHttpClient("typicode", c =>
    {
        c.BaseAddress = new Uri("https://xxx");
        c.DefaultRequestHeaders.Add(
            "accept", "application/json");
    })
    .ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler()
    {
        PooledConnectionLifetime = TimeSpan.FromMinutes(5),
    })
    .SetHandlerLifetime(TimeSpan.FromMinutes(10));

我不太明白为什么需要调用它SetHandlerLifetime(TimeSpan.FromMinutes(10),或者调用它有什么好处?我知道它控制着实例(及其连接池)在“处理程序级别”的重用SetHandlerLifetime时长,以及在“连接级别”的重用时长。SocketsHttpHandlerPooledConnectionLifetime = TimeSpan.FromMinutes(5)

但使用还不够吗PooledConnectionLifetime = TimeSpan.FromMinutes(5),想象一下我使用这个 HttpClient 对不同的 url 进行多个请求,例如 foo1.com、foo2.com......foo10.com,我希望在连接级别上使用 5 分钟的 PooledConnectionIdleTimeout,例如 foo1.com 的连接在 5 分钟后过期,但 foo2.com 仍然处于活动状态并且我想稍后重新使用它,但是 SetHandlerLifetime 会在 10 分钟后清除所有池?

c#
  • 2 2 个回答
  • 68 Views

2 个回答

  • Voted
  1. Best Answer
    Ivan Petrov
    2025-04-26T17:08:34+08:002025-04-26T17:08:34+08:00

    您不会使用它,因为如果您SocketHttpHandler在ConfigurePrimaryHttpMessageHandler/上使用,它本质上是一个冗余的 API UseSocketsHttpHandler。

    这就是为什么微软建议不要同时配置这两个生命周期选项。结合使用 IHttpClientFactory 和 SocketsHttpHandler 的指南如下:

    要使用这两个 API:

    1. 通过ConfigurePrimaryHttpMessageHandler或UseSocketsHttpHandler(仅限.NET 5+)将SocketsHttpHandler指定为PrimaryHandler。
    2. 根据您预期 DNS 更新的间隔设置 SocketsHttpHandler.PooledConnectionLifetime;例如,设置为 HandlerLifetime 中先前的值。
    3. (可选)由于 SocketsHttpHandler 将处理连接池和回收,因此不再需要在 IHttpClientFactory 级别进行处理程序回收。您可以通过设置HandlerLifetime为 来禁用它Timeout.InfiniteTimeSpan。
    services.AddHttpClient(name)
        .UseSocketsHttpHandler((handler, _) =>
            handler.PooledConnectionLifetime = TimeSpan.FromMinutes(2)) // Recreate connection every 2 minutes
        .SetHandlerLifetime(Timeout.InfiniteTimeSpan); // Disable rotation, as it is handled by PooledConnectionLifetime
    

    此外,在 .NET 9 中,HttpClientFactory 使用 SocketsHttpHandler 作为主要处理程序,并且HandlerLifetimeAPI 实际上用于设置PooledConnectionLifetime:

    在支持的平台上SocketsHttpHandler,默认主处理程序现在SocketsHttpHandler设置PooledConnectionLifetime为该HandlerLifetime值。

    但是,根据HttpClientFactory #101808 中的 Make SocketsHttpHandler 作为默认主处理程序,轮换/回收默认情况下不会被禁用(如上述文档片段中所建议):

    贡献#35987(这使得 SocketsHttpHandler 成为默认处理程序,但它不会禁用或下推更高级别的轮换)

    因此,在 .NET 9 中(目前),两个生命周期值默认匹配,在我看来,你会得到一些重复的功能。更多关于默认禁用轮换/回收的讨论,请SocketsHttpHandler参阅IHttpClientFactory“考虑更新 HttpClientFactory 默认值以利用 SocketsHttpHandler #35987”。


    附言:一些可能有用的调试代码

    using Microsoft.Extensions.Http;
    using Microsoft.Extensions.Options;
    
    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddHttpClient("foo")
         .ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler()
         {
             PooledConnectionLifetime = TimeSpan.FromSeconds(6),
         })
         .SetHandlerLifetime(TimeSpan.FromSeconds(5))
         ;
    
    var app = builder.Build();
    app.MapGet("/", (
        IHttpClientFactory clientFactory,
        IOptionsSnapshot<HttpClientFactoryOptions> options) =>
    {
        var client = clientFactory.CreateClient("foo");
        var handler = GetRootHttpHandler(client);
        var socketHttpHandler = handler as SocketsHttpHandler;
        return options.Get("foo").HandlerLifetime.ToString() + " " +
            handler.GetHashCode().ToString() + " " + handler.GetType().ToString() + " " + socketHttpHandler?.PooledConnectionLifetime;
    });
    
    app.Run();
    
    static HttpMessageHandler GetRootHttpHandler(HttpClient client)
    {
        var handlerField = typeof(HttpMessageInvoker)
            .GetField("_handler", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
    
        if (handlerField == null)
            throw new InvalidOperationException("Could not find _handler field.");
    
        var handler = handlerField.GetValue(client) as HttpMessageHandler;
        Console.WriteLine(handler);
    
        if (handler == null)
            throw new InvalidOperationException("Could not retrieve HttpMessageHandler from HttpClient.");
    
        while (handler is DelegatingHandler delegatingHandler)
        {
            handler = delegatingHandler.InnerHandler;
        }
    
        return handler;
    }
    
    • 2
  2. shingo
    2025-04-26T13:55:36+08:002025-04-26T13:55:36+08:00

    你已经知道这一点,但让我重申一下:

    • SetHandlerLifetime用于控制池中处理程序的生命周期IHttpClientFactory

    • PooledConnectionLifetime用于控制处理程序池连接的生存期

    处理程序会存储其访问的站点的 Cookie、证书和连接池,因此如果处理程序过期并被处置,其所有连接也将过期。处理程序的默认生命周期为 2 分钟,因此如果仅将其设置为PooledConnectionLifetime5 分钟则没有意义。

    随着访问的网站越来越多,处理程序占用的内存也会随之增加,这或许就是为什么处理程序会有一个默认的生命周期。所以,如果您不介意内存的增长,可以将生命周期设置为InfiniteTimeSpan。

    • 1

相关问题

  • Polly DecorlatedJitterBackoffV2 - 如何计算完成所有重试所需的最长时间?

  • Wpf。在 ScrollViewer 中滚动 DataGrid

  • 我在使用 .NET MAUI MVVM 的游戏页面上获得的分数在其他页面上不可见。如何在本地设备中保存分数数据

  • 从 DataTemplate 内部将 TreeView 层次结构与 HierarchicalDataTemplate 结合使用

  • 如何改进 .NET 中的验证接口?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve