Sage.Http 2.0.0.11

dotnet add package Sage.Http --version 2.0.0.11
                    
NuGet\Install-Package Sage.Http -Version 2.0.0.11
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Sage.Http" Version="2.0.0.11" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Sage.Http" Version="2.0.0.11" />
                    
Directory.Packages.props
<PackageReference Include="Sage.Http" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Sage.Http --version 2.0.0.11
                    
#r "nuget: Sage.Http, 2.0.0.11"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Sage.Http@2.0.0.11
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Sage.Http&version=2.0.0.11
                    
Install as a Cake Addin
#tool nuget:?package=Sage.Http&version=2.0.0.11
                    
Install as a Cake Tool

Sage.Http

NuGet Version NuGet Downloads License

开源地址: https://gitee.com/liupenglai/sage.http

项目简介

一个简洁、可扩展、支持 DI 与独立模式的 HttpClient 管理库,提供统一配置、稳健的弹性策略(重试、熔断、限流、超时)、事件监控、消息处理器与拦截器,并兼顾线程安全、内存安全与 AOT 友好。

特性

  • 统一管理 HttpClient:支持 ASP.NET Core(DI)与独立模式(WinForms/WPF/控制台)
  • 流式 HttpRequestBuilder:简洁链式 API,内置 JSON 序列化/反序列化,AOT 友好重载
  • 弹性策略:重试、熔断、限流、超时,支持事件观测与订阅
  • 消息处理器与拦截器:推荐工厂重载注册,可灵活注入运行时参数;内置 LoggingHandlerBearerTokenHandlerCorrelationIdHandler
  • 配置即用:JSON 配置(appsettings.json)与环境差异化配置,优雅加载到 HttpClientOptions
  • 事件监控:RetryEventCircuitBreakerEventRateLimiterEvent 等,支持弱引用订阅,避免泄漏
  • 高性能与安全:基于 SocketsHttpHandler 的连接池/HTTP/2,多线程安全,关注内存与线程开销
  • 易扩展:自定义处理器、拦截器、事件处理,可与现有日志/监控系统集成

安装

dotnet add package Sage.Http

快速开始

ASP.NET Core(DI 模式)

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClientManager();

builder.Services.AddHttpClient("github", options =>
{
    options.BaseAddress = new Uri("https://api.github.com");
    options.Timeout = TimeSpan.FromSeconds(30);
    options.AddDefaultHeader("User-Agent", "SageHttpDemo/1.0");

    options.ConfigureRetry(r =>
    {
        r.MaxRetryAttempts = 3;
        r.BaseDelay = TimeSpan.FromSeconds(2);
        r.BackoffType = BackoffType.Exponential;
        r.RetryOnStatusCodes = new HashSet<int> { 408, 429, 500, 502, 503, 504 };
    });

    options.ConfigureCircuitBreaker(cb =>
    {
        cb.FailureRatio = 0.5;
        cb.SamplingDuration = TimeSpan.FromSeconds(30);
        cb.MinimumThroughput = 5;
        cb.BreakDuration = TimeSpan.FromMinutes(1);
    });

    // LoggingHandler(工厂方式自定义级别与体开关)
    options.AddHandler(sp => new LoggingHandler(
        sp.GetRequiredService<ILogger<LoggingHandler>>(),
        requestLogLevel: LogLevel.Information,
        responseLogLevel: LogLevel.Information,
        logRequestBody: false,
        logResponseBody: false));
});

WinForms/控制台(独立模式)

var loggerFactory = LoggerFactory.Create(b =>
{
    b.AddConsole();
    b.SetMinimumLevel(LogLevel.Information);
});
var httpLogger = loggerFactory.CreateLogger<LoggingHandler>();

var manager = StandaloneHttpClientManager.Create(config =>
{
    config.RegisterClient("api", options =>
    {
        options.SetBaseAddress("https://jsonplaceholder.typicode.com")
               .SetTimeout(TimeSpan.FromSeconds(30))
               .ConfigureRetry(r => { r.MaxRetryAttempts = 3; r.BaseDelay = TimeSpan.FromSeconds(1); });

        options.AddHandler(_ => new LoggingHandler(httpLogger,
            requestLogLevel: LogLevel.Information,
            responseLogLevel: LogLevel.Information,
            logRequestBody: false,
            logResponseBody: false));

        options.AddRequestInterceptor(req =>
        {
            req.Headers.TryAddWithoutValidation("X-Trace-Id", Guid.NewGuid().ToString("N"));
        });
    });
});

两种调用方式(并列示例)

原生 HttpClient 与链式 HttpRequestBuilder 均可无缝使用:

// 原生 HttpClient
var client = manager.GetClient("jsonplaceholder");
var post = await client.GetFromJsonAsync<Post>("/posts/1");
await client.PostAsJsonAsync("/posts", new { title = "demo" });

// 链式 HttpRequestBuilder
var posts = await manager
    .CreateRequest("jsonplaceholder", "/posts")
    .WithQuery("_limit", "10")
    .WithHeader("X-Trace-Id", Guid.NewGuid().ToString("N"))
    .GetFromJsonAsync<Post[]>();

// AOT 友好反序列化(JsonTypeInfo<T> 源生成)
var p1 = await manager
    .CreateRequest("jsonplaceholder", "/posts/1")
    .GetFromJsonAsync(typeInfo!);

请求体与表单

  • JSON(AOT 友好):使用 JsonTypeInfo<T> 源生成上下文
var order = new Order { ItemId = 42, Qty = 1 };

// 链式:WithJsonBody + PostAsync
await manager
    .CreateRequest("api", "/orders")
    .WithJsonBody(order, AppJsonContext.Default.Order)
    .PostAsync();

// 便捷:PostAsJsonAsync
await manager
    .CreateRequest("api", "/orders")
    .PostAsJsonAsync(order, AppJsonContext.Default.Order);
  • 表单(AOT 友好):使用 PostAsFormAsync
var form = new Dictionary<string, string> {
    ["username"] = "admin",
    ["password"] = "123456"
};

await manager
    .CreateRequest("api", "/login")
    .PostAsFormAsync(form);
  • 文件上传(Multipart)
using var fs = File.OpenRead("c:/tmp/demo.png");
await manager
    .CreateRequest("api", "/upload")
    .WithFormBody(new Dictionary<string,string> { ["note"] = "hello" })
    .WithFile("file", fs, fileName: "demo.png", contentType: "image/png")
    .PostAsync();
  • 注意:
    • PostAsJsonAsync/…AsFormAsync 不能与 WithXxxBody 混用,否则抛出 InvalidOperationException
    • WithFile 仅在 Multipart 模式有效;若先使用 WithFormBody,添加文件会自动切换到 Multipart。

响应验证与错误处理

  • ValidateAsync:仅校验状态码是否为 2xx;失败抛出 HttpResponseException 或泛型 HttpResponseException<TError>
  • ValidateResponseAsync:校验后返回原始 HttpResponseMessage,便于链式继续解析内容。
  • AOT 提示:
    • ValidateAsync<TError>/ValidateResponseAsync<TError> 仅提供 JsonSerializerOptions 重载,标注为不支持 AOT。
    • AOT 场景优先使用非泛型 ValidateAsync()/ValidateResponseAsync();如需错误对象,建议手动读取正文并使用源生成上下文解析:
// 仅验证(非 2xx 将抛出 HttpResponseException)
await manager
    .CreateRequest("jsonplaceholder", "/posts/404")
    .GetAsync()
    .ValidateAsync();

// 验证并返回响应以继续解析
var response = await manager
    .CreateRequest("jsonplaceholder", "/posts/1")
    .GetAsync()
    .ValidateResponseAsync();
var post = await response.Content.ReadFromJsonAsync<Post>();

// AOT 场景:手动解析错误对象
var bad = await manager
    .CreateRequest("api", "/orders/unknown")
    .GetAsync();
await bad.ValidateResponseAsync(); // 先校验状态码
var json = await bad.Content.ReadAsStringAsync();
var err = JsonSerializer.Deserialize<MyError>(json, AppJsonContext.Default.MyError);

// 直接链式读取(自动校验状态码)
var p1 = await manager
    .CreateRequest("api", "/posts/1")
    .GetAsync()
    .ReadFromJsonAsync(AppJsonContext.Default.Post);

var text = await manager
    .CreateRequest("api", "/posts/1")
    .GetAsync()
    .ReadAsStringAsync();

var bytes = await manager
    .CreateRequest("api", "/image")
    .GetAsync()
    .ReadAsByteArrayAsync();

using var stream = await manager
    .CreateRequest("api", "/file")
    .GetAsync()
    .ReadAsStreamAsync();

配置概览

  • HttpClientOptions
    • 基本:BaseAddressTimeoutHttpVersionDefaultHeadersUseCookiesAllowAutoRedirect
    • 连接:通过 ConfigurePrimaryHandler 使用 SocketsHttpHandler(连接池、Keep-Alive、HTTP/2 多路复用、ConnectTimeout)
  • 弹性策略(ResilienceOptions
    • 重试:MaxRetryAttemptsBaseDelayBackoffTypeUseJitter;基于状态码/范围/异常/ShouldRetry
    • 熔断:FailureRatioSamplingDurationMinimumThroughputBreakDuration
    • 限流:PermitLimitWindowQueueLimit
    • 超时:客户端级与策略级均可配置
    • 事件:启用后可订阅 RetryEventCircuitBreakerEventRateLimiterEvent

消息处理器与拦截器

  • 处理器(推荐在 DI 模式):LoggingHandlerCorrelationIdHandlerBearerTokenHandlerCustomHeaderHandlerUserAgentHandler
  • 注册方式
    • 泛型:options.AddHandler<THandler>()(构造参数由 DI 解析,适合无自定义运行时参数)
    • 工厂:options.AddHandler(sp => new Handler(...))(推荐,可自定义参数,DI 与独立模式均适用)
  • 拦截器:AddRequestInterceptorAddResponseInterceptorAsyncAddErrorInterceptor;更轻量,适合观测与简单变更
  • 提示:避免同时用拦截器与 LoggingHandler 记录同类日志,否则可能重复输出

JSON 配置示例(appsettings.json)

{
  "HttpClients": {
    "github": {
      "BaseAddress": "https://api.github.com",
      "Timeout": "00:00:30",
      "HttpVersion": "2.0",
      "DefaultHeaders": { "User-Agent": "SageHttpDemo/1.0" },
      "Resilience": {
        "EnableRetry": true,
        "Retry": { "MaxRetryAttempts": 3, "BaseDelay": "00:00:02", "BackoffType": "Exponential" },
        "EnableCircuitBreaker": true,
        "CircuitBreaker": { "FailureRatio": 0.5, "SamplingDuration": "00:00:30", "MinimumThroughput": 5, "BreakDuration": "00:01:00" },
        "EnableEvents": true
      }
    }
  }
}

加载:builder.Services.AddHttpClient("github", builder.Configuration.GetSection("HttpClients:github").Get<HttpClientOptions>());

事件订阅

// 特定客户端
_manager.Subscribe<RetryEvent>("github", e => Debug.WriteLine($"Retry {e.AttemptNumber}: {e.RequestUri}"));

// 所有客户端
_manager.Subscribe<HttpClientEvent>(e => Console.WriteLine($"{e.GetType().Name}: {e.ClientName}"));

// 弱引用(避免内存泄漏)
_manager.Subscribe<RetryEvent>("api", OnRetry, useWeakReference: true);

使用场景

  • 第三方 API:启用重试与 LoggingHandler,便于排查问题
  • 微服务:BearerTokenHandler + CorrelationIdHandler + 熔断与重试
  • 批量下载:限流(并发与队列限制)、长超时、响应流式读取

性能与故障排查

  • 建议使用 GetClient 复用实例;避免在循环中频繁 CreateClient
  • 启用 HTTP/2 与连接池参数优化(SocketsHttpHandler
  • 日志排查:LoggingHandlerlogRequestBody/logResponseBody 仅在调试场景启用,注意敏感信息脱敏
  • 常见问题与更多排查步骤详见 Troubleshooting.md

文档导航

示例

许可证

Apache-2.0

本项目采用 Apache License 2.0 开源协议。详情见 LICENSE.txt

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Sage.Http:

Package Downloads
Sage.CloudStorage.Qiniu

Sage.CloudStorage.Qiniu 是一个基于 .NET 平台的现代化七牛云存储 SDK,采用完全异步设计,提供了对七牛云对象存储、CDN 等服务的简单易用的 API 封装。该库基于 Sage.Http 构建,具有高性能、可扩展的七牛云服务访问能力,特别适合企业级应用和大文件处理场景。 ## 核心优势 - **现代化API设计**:完全异步,符合.NET最佳实践 - **模块化架构**:各组件职责明确,易于扩展和维护 - **丰富的事件机制**:提供上传进度通知和完成事件 - **智能上传策略**:自动选择最佳上传方式和分片大小 - **完善的错误处理**:提供详细的错误信息和恢复机制 ## 功能特性 - **完整的对象存储支持**:上传、下载、管理、删除等操作 - **高级上传功能**: - 智能分片上传(自动优化分片大小) - 断点续传支持 - 并发控制 - 实时进度监控 - **CDN管理**:刷新、预取、带宽查询、日志下载 - **数据处理**:图片处理、音视频转码等 - **批量操作**:批量上传、删除等

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0.11 104 1/14/2026
2.0.0.10 150 12/12/2025
2.0.0.9 440 11/18/2025
2.0.0.8 225 10/27/2025
2.0.0.7 142 10/25/2025
2.0.0.6 149 10/25/2025
2.0.0.5 145 10/25/2025
2.0.0.4 138 10/25/2025
2.0.0.3 150 10/25/2025
2.0.0.2 178 10/24/2025
2.0.0.1 210 10/23/2025
2.0.0 211 10/23/2025
1.0.1.25 209 10/19/2025
1.0.1.24 211 10/19/2025
1.0.1.23 292 10/19/2025 1.0.1.23 is deprecated because it has critical bugs.
1.0.1.22 294 10/19/2025 1.0.1.22 is deprecated because it has critical bugs.
1.0.1.21 298 10/19/2025 1.0.1.21 is deprecated because it has critical bugs.
1.0.1.20 300 10/19/2025 1.0.1.20 is deprecated because it has critical bugs.
1.0.1.19 209 10/15/2025
1.0.1.18 208 10/13/2025
Loading failed

更新基础库