要在 .NET 中使用速率限制,请引用 System.Threading.RateLimiting NuGet 包
使用示例
//HttpClient client = new HttpClient();
HttpClient client = StaticHttpClient._client;
client.DefaultRequestHeaders.Accept.Clear();
string region = host_platform.GetHostFromPlatform(platform);
var url = $"https://{region}/lol/summoner/v4/summoners/{sid}";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Add("X-Riot-Token", UserSearch.api_key);
var ms = await client.SendAsync(request);
var json = await ms.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<Summoner>(json);
代码
internal class StaticHttpClient
{
static StaticHttpClient()
{
var options = new TokenBucketRateLimiterOptions
{
TokenLimit = 100,
QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
QueueLimit = 100,
ReplenishmentPeriod = TimeSpan.FromSeconds(0.05),///1.2s //0.05
TokensPerPeriod = 200,
AutoReplenishment = true
};
// Create an HTTP client with the client-side rate limited handler.
_client = new HttpClient(new ClientSideRateLimitedHandler(new TokenBucketRateLimiter(options)));
}
public static HttpClient _client { get; set; }
}
internal sealed class ClientSideRateLimitedHandler : DelegatingHandler, IAsyncDisposable
{
RateLimiter limiter;
public ClientSideRateLimitedHandler(RateLimiter _limiter) : base(new HttpClientHandler())
{
limiter = _limiter;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
using (RateLimitLease lease = await limiter.AcquireAsync(permitCount: 1, cancellationToken))
{
if (lease.IsAcquired)
{
return await base.SendAsync(request, cancellationToken);
}
var response = new HttpResponseMessage((System.Net.HttpStatusCode)429);
if (lease.TryGetMetadata(
MetadataName.RetryAfter, out TimeSpan retryAfter))
{
response.Headers.Add(
"Retry-After",
((int)retryAfter.TotalSeconds).ToString(
NumberFormatInfo.InvariantInfo));
}
return response;
}
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
await limiter.DisposeAsync().ConfigureAwait(false);
Dispose(disposing: false);
GC.SuppressFinalize(this);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
limiter.Dispose();
}
}
}
核心参数解释:
1.ReplenishmentPeriod:令牌补充的时间间隔(如 TimeSpan.FromSeconds(1) 表示每隔1秒补充一次)
2.TokensPerPeriod:每个补充周期添加的令牌数量(如设置为10,则每秒补充10个令牌)
3.TokenLimit:令牌桶的容量上限(如设为100,桶内令牌数最多为100)
实际允许的请求速率由 TokensPerPeriod / ReplenishmentPeriod 计算得出。例如:
若 ReplenishmentPeriod = 1秒, TokensPerPeriod = 10 → 每秒允许10次请求
参考
https://learn.microsoft.com/zh-cn/dotnet/core/extensions/http-ratelimiter