SignalR启用HTTPS后跨服务器连接时拒绝客户端连接问题
SignalR HTTPS 跨服务器连接后拒绝客户端请求的问题解决
问题场景
搭建了一组兼具发布者与订阅者角色的SignalR服务器,同时接收普通客户端连接:
- HTTP协议下所有功能正常
- 切换为自签证书的HTTPS后,单台服务器未连接其他服务器时可正常接收任意客户端连接;但服务器间建立连接后,所有客户端调用
await _hubConnection.Start()时均抛出**"An existing connection was forcibly closed by the remote host"**异常 - 建立Hub连接前使用
SslStream.AuthenticateAsClientAsync(host)验证证书时,也会出现相同异常,仅单服务器运行时正常
核心原因
问题根源在于错误地将其他服务器的证书绑定到了本地服务器的HTTPS端口。SignalR服务器作为HTTPS服务端时,仅需绑定自身的有效证书;而作为订阅者(以客户端角色连接其他服务器)时,只需持有并信任目标服务器的证书,无需将其绑定到本地端口。
解决方案
1. 修正本地端口的证书绑定
- 查看当前HTTPS端口的证书绑定情况:
netsh http show sslcert - 确认绑定的证书Thumbprint是否为本地服务器的自签证书,若绑定了其他服务器的证书,先删除错误绑定:
netsh http delete sslcert ipport=0.0.0.0:你的HTTPS端口 - 重新绑定本地服务器的证书(替换占位符为实际值):
netsh http add sslcert ipport=0.0.0.0:你的HTTPS端口 certhash=本地证书Thumbprint appid={你的应用GUID}
2. 调整服务器作为SignalR客户端的配置
当服务器以订阅者角色连接其他服务器时,只需在HubConnection配置中处理证书信任或指定客户端证书,无需绑定到本地端口。示例代码:
var hubConnection = new HubConnectionBuilder() .WithUrl("https://目标服务器地址/valuehub", options => { // 测试环境下信任所有自签证书(生产环境需验证证书链) options.HttpMessageHandlerFactory = handler => { var clientHandler = handler as HttpClientHandler; clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true; return clientHandler; }; // 若需双向认证,直接加载客户端证书即可 options.ClientCertificates.Add(new X509Certificate2("本地客户端证书.pfx", "证书密码")); }) .Build();
3. 补充检查项
- 将所有服务器的自签证书导入到对方的受信任根证书颁发机构,避免证书链验证失败
- 确认服务器间的防火墙规则已开放HTTPS端口的双向通信
- 检查SignalR日志,确保WebSocket传输在HTTPS下正常启用(WebSocket是SignalR的默认首选传输方式)
原始服务器配置代码
if (CommonServiceLocator.ServiceLocator.Current.GetInstance<XAMComSettings>().PubSubEnabled) { GlobalHost.HubPipeline.AddModule(new ErrorHandlingPipelineModule(CommonServiceLocator.ServiceLocator.Current.GetInstance<ILogger<ValueHub>>())); GlobalHost.Configuration.MaxIncomingWebSocketMessageSize = null; app.Map(ValueClientConfig.VALUE_HUB_URL, map => { map.UseCors(CorsOptions.AllowAll) .RunSignalR(new HubConfiguration { EnableDetailedErrors = true }); }); } var config = new HttpConfiguration(); config.MapHttpAttributeRoutes(); config.EnableSwagger(c => { c.SingleApiVersion("1.0.0", "PubSub Diagnostics"); }).EnableSwaggerUi(); config.Services.Add(typeof(IExceptionLogger), new DiagnosticsExceptionLogger(CommonServiceLocator.ServiceLocator.Current.GetInstance<ILoggerFactory>().CreateLogger<DiagnosticsExceptionLogger>())); config.Filters.Add(new ThrottlingFilter { Policy = new ThrottlePolicy { IpThrottling = true, ClientThrottling = true, EndpointThrottling = true }, Repository = new MemoryCacheRepository() }); app.UseCors(CorsOptions.AllowAll); app.UseWebApi(config);
内容的提问来源于stack exchange,提问作者Phil True
相关产品推荐
相关产品推荐

