如何获取SignalR Core接收消息的实际大小?优先支持IHubFilter实现
跟踪SignalR Core传入消息的实际大小
可以通过自定义HubProtocol包装器结合IHubFilter实现消息大小的跟踪,以下是具体方案:
1. 实现自定义HubProtocol包装器
这个包装器会在解析消息时记录原始消息的字节长度,并将长度存入HubCallerContext的Items集合,供后续过滤器调用:
public class SizeTrackingHubProtocol : IHubProtocol { private readonly IHubProtocol _innerProtocol; public SizeTrackingHubProtocol(IHubProtocol innerProtocol) { _innerProtocol = innerProtocol; } public string Name => _innerProtocol.Name; public int Version => _innerProtocol.Version; public TransferFormat TransferFormat => _innerProtocol.TransferFormat; public ReadOnlyMemory<byte> GetMessageBytes(HubMessage message) { return _innerProtocol.GetMessageBytes(message); } public HubMessage ParseMessage(ReadOnlySequence<byte> input, IInvocationBinder binder) { var messageSize = input.Length; if (HubCallerContext.Current is { } context) { context.Items["IncomingMessageSize"] = messageSize; } return _innerProtocol.ParseMessage(input, binder); } public async ValueTask<HubMessage> ParseMessageAsync(Stream input, IInvocationBinder binder, CancellationToken cancellationToken = default) { var memoryStream = new MemoryStream(); await input.CopyToAsync(memoryStream, cancellationToken); memoryStream.Position = 0; var messageSize = memoryStream.Length; if (HubCallerContext.Current is { } context) { context.Items["IncomingMessageSize"] = messageSize; } return await _innerProtocol.ParseMessageAsync(memoryStream, binder, cancellationToken); } }
2. 实现IHubFilter获取并跟踪消息大小
在过滤器中从HubCallerContext.Items取出记录的消息大小,即可完成日志记录、统计等跟踪操作:
public class MessageSizeTrackingFilter : IHubFilter { private readonly ILogger<MessageSizeTrackingFilter> _logger; public MessageSizeTrackingFilter(ILogger<MessageSizeTrackingFilter> logger) { _logger = logger; } public async ValueTask<object> OnInvokingAsync(HubInvocationContext invocationContext, Func<ValueTask<object>> next) { if (invocationContext.Context.Items.TryGetValue("IncomingMessageSize", out var sizeObj) && sizeObj is long messageSize) { // 此处可根据需求处理消息大小,比如日志记录、指标上报 _logger.LogInformation("收到SignalR消息,大小:{Size}字节,调用方法:{Method}", messageSize, invocationContext.HubMethodName); } return await next(); } }
3. 注册自定义组件
在Program.cs中注册自定义的HubProtocol和IHubFilter:
builder.Services.AddSignalR(options => { options.MaximumReceiveMessageSize = 32768; }) .AddHubProtocol(() => { // 包装默认的JSON协议,若使用MessagePack可替换为对应的协议实现 return new SizeTrackingHubProtocol(new JsonHubProtocol()); }) .AddFilter<MessageSizeTrackingFilter>();
注意事项
- 若使用多种Hub协议,需分别包装对应协议实现
- WebSocket传输通过
ParseMessage直接处理字节序列,长轮询等HTTP传输通过ParseMessageAsync读取完整请求体计算大小 - 如需跟踪连接建立时的初始消息,可在Hub的
OnConnectedAsync方法中读取Context.Items中的大小值
内容的提问来源于stack exchange,提问作者Shad
相关产品推荐
相关产品推荐

