SignalR客户端与服务端版本兼容异常求助
问题核心分析
你遇到的错误"You are using a version of the client that isn't compatible with the server. Client version 1.5, server version undefined",本质是服务器端SignalR组件版本不一致,加上可能的前端JS加载异常,导致握手时版本校验失败。你的后端混合使用了1.2.2和2.2.3版本的SignalR包,这是最可能的根源。
分步解决方案
1. 统一后端所有SignalR包版本
当前后端依赖的SignalR包版本混乱:Microsoft.AspNet.SignalR.Client和Microsoft.AspNet.SignalR.Owin是1.2.2,而Core和SystemWeb是2.2.3。这种混合版本会导致服务器内部处理握手请求时,返回的版本信息异常(出现undefined)。
操作:
- 在NuGet包管理器中,将所有
Microsoft.AspNet.SignalR.*相关包统一升级到2.2.3版本,确保没有遗漏任何SignalR相关依赖。
2. 确保前端仅加载正确版本的SignalR JS
错误中显示客户端版本为1.5,说明前端可能加载了旧版本的SignalR脚本(可能是页面中存在多个版本引用,或者缓存了旧脚本)。
操作:
- 检查
index.html中SignalR JS的引用,确认是v2.2.3,并且没有其他地方引入了旧版本的jquery.signalR-x.x.x.js。 - 强制清除浏览器缓存,或者给脚本URL添加版本号(比如
/scripts/jquery.signalR-2.2.3.js?v=20240520),避免缓存旧脚本。
3. 修复前端连接重试逻辑
当前代码只在$.connection不存在时重试,但连接失败(fail回调)时没有重试逻辑,且重试间隔固定500ms,容易导致频繁请求加重服务器负担。
修改后的前端代码:
startHub(self) { if ($.connection && $.connection.hub && $.connection.userNotificationHub) { $.connection.hub.url = Util.url + 'signalr'; $.connection.hub.logging = true; $.connection.userNotificationHub.client.onLogoutCustomMessage = self.onLogoutCustom; const startConnection = () => { $.connection.hub.start() .done(function (connection) { console.log('Service Started', connection.id); self.retryCount = 0; // 连接成功重置重试计数 }) .fail(function (error) { console.log('Could not Connect!', error); // 指数退避重试:1s, 2s, 4s... 最多到30s const retryDelay = Math.min(Math.pow(2, self.retryCount || 0) * 1000, 30000); self.retryCount = (self.retryCount || 0) + 1; setTimeout(() => startConnection(), retryDelay); }); }; startConnection(); } else { setTimeout(() => self.startHub(self), 1000); } }
4. 启用CORS(如果存在跨域场景)
如果前端和后端部署在不同域名下,必须启用CORS,否则握手请求会被浏览器拦截,可能表现为版本不兼容的错误。
修改后端Startup.cs代码,启用CORS:
public void Configuration(IAppBuilder app) { GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(3600); app.Map("/signalr", map => { // 启用CORS,允许所有来源(生产环境建议限制特定域名) map.UseCors(CorsOptions.AllowAll); var hubConfiguration = new HubConfiguration { EnableJavaScriptProxies = true, EnableDetailedErrors = true }; map.RunSignalR(hubConfiguration); }); }
5. 可选:关闭JavaScript代理,手动指定Hub名称
如果启用EnableJavaScriptProxies导致代理生成异常,可以尝试关闭代理,手动指定Hub名称,避免版本相关的代理问题。
修改前端连接代码:
// 关闭自动代理,手动创建Hub连接 const hubConnection = $.hubConnection(Util.url + 'signalr'); const userNotificationHub = hubConnection.createHubProxy('userNotificationHub'); userNotificationHub.on('onLogoutCustomMessage', self.onLogoutCustom); hubConnection.logging = true; hubConnection.start() .done(connection => console.log('Service Started', connection.id)) .fail(error => console.log('Could not Connect!', error));
修改后端HubConfiguration:
var hubConfiguration = new HubConfiguration { EnableJavaScriptProxies = false, // 关闭自动代理 EnableDetailedErrors = true };
额外排查点
- 检查服务器日志:启用
EnableDetailedErrors后,服务器会输出更详细的错误信息,查看是否有握手阶段的异常日志。 - 检查网络请求:在浏览器开发者工具中查看SignalR的握手请求(
/signalr/negotiate),查看返回的ProtocolVersion是否为2.2.3,如果返回异常,说明服务器端版本仍有问题。
内容的提问来源于stack exchange,提问作者Ankit Singh

