2.23接口调用配额限制
在与第三方 API(如微信、支付网关等)集成时,通常需要遵守其每日/每月调用次数限制。为避免因超限导致业务中断或封禁,框架提供了灵活的接口调用配额限制功能,支持按天、按周、按月、永久总次数等策略,并允许自定义策略。
在与第三方 API(如微信、支付网关等)集成时,通常需要遵守其每日/每月调用次数限制。为避免因超限导致业务中断或封禁,框架提供了灵活的接口调用配额限制功能,支持按天、按周、按月、永久总次数等策略,并允许自定义策略。
启用配额限制后,每次请求会根据配置的策略检查当前计数,若达到上限将直接中断请求并抛出 InvalidOperationException 异常(不会实际发送 HTTP 请求)。通过 HttpRequestBuilder.SetQuotaKey(key) 为每个请求指定配额键,并与 HttpClientOptions 中的配额配置关联。
配置方式#
1. 注册默认配额策略#
在 Startup.cs 或 Program.cs 文件中注册默认配额策略:
services.AddHttpRemote(builder =>{ builder.AddDefaultQuotaStrategies(); // 注册 daily、weekly、monthly、lifetime 四种策略});2. 为指定 HttpClient 客户端配置配额限制#
在注册 HttpClient 时,通过 ConfigureOptions 设置 QuotaLimits 字典,将配额键与对应的限制策略关联:
// 配置默认客户端services.AddHttpClient(string.Empty) .ConfigureOptions(options => // 或使用重载:.ConfigureOptions((options, serviceProvider) => { options.QuotaLimits = new Dictionary<string, HttpQuotaLimit> { ["wechat/accesstoken"] = new HttpQuotaLimit("daily", 2000), // 每日限额 ["wechat/menu_create"] = new HttpQuotaLimit("weekly", 1000), // 每周限额 ["wechat/upload_media"] = new HttpQuotaLimit("monthly", 50000), // 每月限额 ["wechat/lifetime_stat"] = new HttpQuotaLimit("lifetime", 10000) // 生命周期总额 }; });// 配置特定客户端services.AddHttpClient("weixin") .ConfigureOptions(options => // 或使用重载:.ConfigureOptions((options, serviceProvider) => { options.QuotaLimits = new Dictionary<string, HttpQuotaLimit> { ["wechat/accesstoken"] = new HttpQuotaLimit("daily", 2000), // 每日限额 ["wechat/menu_create"] = new HttpQuotaLimit("weekly", 1000), // 每周限额 ["wechat/upload_media"] = new HttpQuotaLimit("monthly", 50000), // 每月限额 ["wechat/lifetime_stat"] = new HttpQuotaLimit("lifetime", 10000) // 生命周期总额 }; });3. 为请求指定配额键#
在发送请求时,使用 SetQuotaKey 关联到对应的配额配置,使该请求受对应规则的约束:
var response = await httpRemoteService.SendAsync( HttpRequestBuilder.Get("https://api.weixin.qq.com/cgi-bin/token") .SetHttpClientName("weixin") .SetQuotaKey("wechat/accesstoken")); // 此键限制为每日 2000 次内置配额策略#
框架内置了四种常用策略,通过 Strategy 属性指定(大小写不敏感):
| 策略名称 | 说明 | 窗口重置规则(基于 UTC 时间) |
|---|---|---|
daily | 每日限额 | 每天 00:00:00 重置 |
weekly | 每周限额 | 每周一 00:00:00 重置 |
monthly | 每月限额 | 每月第一天 00:00:00 重置 |
lifetime | 生命周期总额(不按时间重置) | 永不重置,达到上限后永久拒绝 |
例如,配置 Strategy = "daily",MaxCount = 2000 表示每天最多调用 2000 次。配置 Strategy = "lifetime",MaxCount = 10000 表示该配额键在整个应用生命周期内最多调用 10000 次,不会随时间重置。
自定义配额策略#
您可以实现 IHttpQuotaStrategy 接口来创建任意重置规则的策略(例如按小时、按自定义时间窗口、基于滑动窗口等)。
1. 定义策略类
public sealed class HourlyQuotaStrategy : IHttpQuotaStrategy{ /// <inheritdoc /> public string Name => "hourly"; // 策略的唯一名称 /// <inheritdoc /> public bool TryAcquire(HttpQuotaCounter quotaCounter, int maxCount, out int current) { // 以 UTC 当前小时作为窗口标识(格式:yyyy-MM-dd HH) var hourKey = DateTime.UtcNow.ToString("yyyy-MM-dd HH"); // 如果窗口标识改变,说明进入新的小时,重置计数 if (quotaCounter.WindowKey != hourKey) { quotaCounter.Count = 0; quotaCounter.WindowKey = hourKey; } // 递增计数 quotaCounter.Count++; current = quotaCounter.Count; return current <= maxCount; }}2. 注册自定义配额策略
在 Startup.cs 或 Program.cs 文件中注册自定义配额策略:
services.AddHttpRemote(builder =>{ builder.AddQuotaStrategy<HourlyQuotaStrategy>();});注册后,即可在 QuotaLimits 中使用 Strategy = "hourly":
options.QuotaLimits = new Dictionary<string, HttpQuotaLimit>{ ["some/high_freq_api"] = new HttpQuotaLimit("hourly", 100) // 每小时最多调用 100 次};多节点集群部署#
默认情况下,配额管理器 HttpQuotaManager 基于内存缓存维护计数器,适用于单节点或单实例部署。在多节点集群环境中,每个节点各自维护独立的计数状态,导致整体配额限制失效(例如某接口全局限额 2000 次/天,各节点可能分别调用 2000 次而未互相感知)。为使配额在所有节点间准确共享,可将计数器存储迁移至分布式缓存(如 Redis)。
只需实现 IHttpQuotaManager 接口,将计数和窗口检查逻辑依托于分布式原子操作,然后替换默认服务即可:
public class RedisHttpQuotaManager : IHttpQuotaManager{ // 实现接口方法,基于 Redis 实现原子递增、窗口重置和超限检查}在服务注册时替换默认实现:
services.Replace(ServiceDescriptor.Singleton<IHttpQuotaManager, RedisHttpQuotaManager>());替换后,所有节点共享同一份配额计数器,确保集群全局的调用次数始终在配置的限制之内。自定义实现时,务必保证窗口重置与计数递增的原子性,避免并发导致超限。
通过以上机制,您可以轻松地为不同接口配置差异化的调用限额,有效防止因过度调用而触发的第三方 API 限制或费用超额问题。