如何为SignalR Hub方法配置生效的限流中间件?
问题原因
ASP.NET Core 自带的 Rate Limiting 中间件仅针对HTTP 请求管道生效,而 SignalR Hub 方法的调用是基于已建立的长连接(如 WebSocket)进行的消息交互,不会经过 HTTP 中间件管道,因此直接给 Hub 方法添加 [EnableRateLimiting] 特性无法触发限流逻辑。
解决方案
通过实现 SignalR 的 IHubFilter 过滤器,在 Hub 方法调用前手动集成限流策略,复用你已配置的 "fixed" 限流规则。
1. 自定义限流 Hub 过滤器
创建过滤器类,在方法调用前检查限流状态:
using Microsoft.AspNetCore.RateLimiting; using Microsoft.AspNetCore.SignalR; using System.Reflection; using System.Threading.RateLimiting; public class RateLimitingHubFilter : IHubFilter { private readonly IRateLimiterFactory _rateLimiterFactory; public RateLimitingHubFilter(IRateLimiterFactory rateLimiterFactory) { _rateLimiterFactory = rateLimiterFactory; } public async ValueTask<object?> InvokeMethodAsync(HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object?>> next) { // 检查当前方法是否标记了限流特性 var rateLimitAttr = invocationContext.Method .GetCustomAttribute<EnableRateLimitingAttribute>(); if (rateLimitAttr == null) { return await next(invocationContext); } // 获取已配置的限流器(复用你定义的"fixed"策略) var limiter = _rateLimiterFactory.GetRateLimiter(rateLimitAttr.PolicyName); // 用用户ID作为限流键(无用户则用连接ID) var limitKey = invocationContext.Context.UserIdentifier ?? invocationContext.Context.ConnectionId; // 尝试获取限流许可 using var lease = await limiter.AcquireAsync(limitKey); if (!lease.IsAcquired) { // 触发限流时抛出异常,前端会收到错误消息 throw new HubException("请求过于频繁,请稍后重试。"); } // 许可获取成功,执行原方法 return await next(invocationContext); } }
2. 注册过滤器到 SignalR
在 Program.cs 中,将自定义过滤器添加到 SignalR 的配置里:
var builder = WebApplication.CreateBuilder(args); // 保留你原有的限流配置 builder.Services.AddRateLimiter(_ => _ .AddFixedWindowLimiter(policyName: "fixed", options => { options.PermitLimit = 4; options.Window = TimeSpan.FromSeconds(12); options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; options.QueueLimit = 2; })); // 注册SignalR并添加限流过滤器 builder.Services.AddSignalR(options => { options.AddFilter<RateLimitingHubFilter>(); }); var app = builder.Build(); app.UseRateLimiter(); // 注册你的SignalR Hub端点(示例) app.MapHub<YourHub>("/your-hub"); app.Run();
3. 验证限流效果
保持你原有的 Hub 方法标记:
[EnableRateLimiting("fixed")] public Task Test() { // 方法逻辑 return Task.CompletedTask; }
当同一用户/连接在12秒内调用 Test 方法超过4次时,会触发限流并抛出异常,前端可捕获该错误提示用户。
内容的提问来源于stack exchange,提问作者Tomorrow will be better
相关产品推荐
相关产品推荐

