.NET Core集群中使用WebSocket时HttpContext丢失问题求助
求助:SignalR+Rebus+Cloudflare负载均衡下HttpContext为空问题
配置情况
- 三台配置完全一致的Windows服务器,部署多个基于.NET 8和IIS的C# API,同时部署RabbitMQ集群
- 使用Cloudflare作为负载均衡器,未启用会话亲和性(因不想使用代理)
问题描述
API通过Rebus以localhost方式连接本地RabbitMQ实例,集群消息自动分发。核心配置代码如下:
[...] services .AddSignalR( _ => { _.EnableDetailedErrors = true; } ) .AddMessagePackProtocol( _ => { _.SerializerOptions = MessagePackSerializerOptions.Standard .WithSecurity( MessagePackSecurity.UntrustedData ); } ) .AddRebusBackplane<myhub>(); // 已脱敏 [...] string rabbitMqConnectionString = $"amqp://rabbit:carrot@localhost:5672/myvhost"; // 已脱敏 services.AddRebus( configure => configure .Transport( x => { x.UseRabbitMq( rabbitMqConnectionString, GenerateTransientQueueName( "queuename" ) ) .InputQueueOptions( o => { o.SetAutoDelete( true ); o.SetDurable( false ); } ); } ) ); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); [...] app.UseEndpoints( endpoints => { endpoints.MapControllers(); endpoints.MapHub<myhub>( "/myhub" ); // 已脱敏 } ); [...]
通过NextJS应用的SignalR Hub访问API时,经负载均衡器刷新几次后,即使目标主机未改变,HttpContextAccessor.HttpContext突然为空。报错触发代码片段:
[...] _httpContextAccessor = httpContextAccessor; _context = context; _securityService = securityService; Claim[]? claims = _httpContextAccessor.HttpContext?.User.Claims.ToArray(); if (_httpContextAccessor == null) throw new Exception( "Httpcontextaccessor is null" ); if (_httpContextAccessor.HttpContext == null) throw new Exception( "Httpcontextaccessor => Httpcontext is null" ); // <-- 触发此异常 if (_httpContextAccessor.HttpContext.User == null) throw new Exception( "Httpcontextaccessor => Httpcontext => User is null" ); if (claims == null) { throw new Exception( "Cant access Http Context!" ); } [...]
排查信息:
- 未使用Rebus、RabbitMQ或SignalR的API运行正常,无此问题,怀疑问题出在Rebus或RabbitMQ环节
- RabbitMQ日志和管理界面无异常,三台API服务器均已正常连接
- 绕开负载均衡器直接访问时,问题不再出现
更新内容
定位到SignalR客户端协商请求环节:负载均衡器在协商后返回不同服务器(因未启用粘性会话,高流量时会重定向流量)。通过客户端关闭协商后,问题无法复现,JS配置代码如下:
const connection = new HubConnectionBuilder() .withUrl(`${process.env.NEXT_PUBLIC_API_BASEURI}/${global.endpoints.myhub}`, { accessTokenFactory: () => mytoken, skipNegotiation: true, // 新增配置 transport: HttpTransportType.WebSockets, // 新增配置 }) .withHubProtocol(new MessagePackHubProtocol()) .withAutomaticReconnect() .build();
注:关闭协商前需参考微软官方安全建议。
现寻求针对该问题的进一步专业技术建议。
内容的提问来源于stack exchange,提问作者DevShadow
相关产品推荐
相关产品推荐

