SignalR实现API事件触发通知时遇连接拒绝问题求助
解决SignalR连接拒绝错误及前端消息展示问题
Hey there! 看你现在卡在了SignalR连接拒绝(ERR_CONNECTION_REFUSE)的问题上,同时之前的前端代码也有小疏漏,我来一步步帮你理清解决思路:
一、先搞定当前的连接拒绝错误
这个错误的核心原因是你的SignalR服务端没有正确响应客户端的连接请求,你可以按以下步骤排查:
1. 确认服务端的SignalR路由配置是否正确
这是最容易忽略的点:
- 如果是ASP.NET MVC 5及更早版本:在
Global.asax的Application_Start方法里,必须添加SignalR的路由映射:
protected void Application_Start() { // 其他配置... RouteTable.Routes.MapHubs(); // 一定要加这行! }
- 如果是ASP.NET Core版本:路由配置方式不一样,要在
Startup.cs的Configure方法里指定Hub的路径:
app.UseSignalR(routes => { routes.MapHub<NotificationHub>("/notificationHub"); });
另外,Core版本里不能再用GlobalHost获取IHubContext了,要通过依赖注入:
public class NotificationHub : Hub { private readonly IHubContext<NotificationHub> _hubContext; // 通过构造函数注入 public NotificationHub(IHubContext<NotificationHub> hubContext) { _hubContext = hubContext; } // 推荐把Send改成实例方法,或者在需要触发通知的地方直接注入IHubContext public async Task Send(string content) { await _hubContext.Clients.All.SendAsync("addMessage", content); } }
2. 确认客户端请求的地址和服务端匹配
你控制台里的请求地址是http://127.0.0.1:8080/signalr/negotiate,要检查:
- 你的服务端真的运行在
8080端口吗?如果是IIS Express,默认端口可能不是这个,去项目属性里看看端口设置。 - 如果是ASP.NET Core,SignalR的默认路由不是
/signalr,而是你MapHub里配置的路径,这时候客户端连接代码要改成:
// Core版本的客户端连接写法 var conn = new signalR.HubConnectionBuilder() .withUrl("/notificationHub") // 对应服务端配置的路径 .build();
3. 检查跨域配置(如果前端和API不在同一域名/端口)
如果你的前端页面和SignalR服务端不在同一端口或域名,必须配置跨域允许:
- ASP.NET MVC 5:用
Microsoft.Owin.Cors包,在Owin的Startup.cs里配置:
public void Configuration(IAppBuilder app) { app.UseCors(CorsOptions.AllowAll); app.MapHubs(); }
- ASP.NET Core:在
Startup.cs的ConfigureServices里添加跨域策略:
services.AddCors(options => { options.AddPolicy("AllowAll", builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials()); });
然后在Configure里启用:
app.UseCors("AllowAll"); app.UseSignalR(...);
二、前端消息展示的正确写法
你之前的前端代码有个关键缺失:没有启动连接!而且可以优化消息展示的方式,比如显示在页面里而不只是alert:
$(document).ready(function () { // SignalR 2.x(对应MVC5)的写法:注意Hub名是驼峰式的notificationHub var conn = $.connection.notificationHub; // 定义接收消息的方法,要和服务端调用的addMessage完全对应 conn.client.addMessage = function (message) { // 把消息添加到页面的某个容器里,比如id为notificationList的ul $("#notificationList").append(`<li>新通知:${message}</li>`); // 保留alert用于测试也可以 alert(message); }; // 必须调用start()启动连接!之前的代码漏掉了这一步! $.connection.hub.start() .done(() => console.log("SignalR连接成功啦!")) .fail(err => console.error("连接失败:", err)); });
记得在页面里加个用于展示通知的容器:
<ul id="notificationList"></ul>
三、服务端触发通知的优化建议
你的onTick静态方法调用NotificationHub.Send的方式,在MVC5里可以用,但在Core里不行,更推荐的做法是在需要触发通知的地方直接注入IHubContext:
public class YourController : Controller { private readonly IHubContext<NotificationHub> _hubContext; // 通过构造函数注入IHubContext public YourController(IHubContext<NotificationHub> hubContext) { _hubContext = hubContext; } public async void onTick(Tick TickData) { if(TickData.InstrumentToken == buy.InstrumentToken) { // Core里用SendAsync,MVC5里用Clients.All.addMessage await _hubContext.Clients.All.SendAsync("addMessage", TickData.Bid.ToString()); } } }
最后总结下解决步骤
- 先确认服务端的SignalR路由配置是否正确,有没有加
MapHubs(MVC5)或MapHub(Core)。 - 补上前端代码里的
$.connection.hub.start()调用,启动连接。 - 检查服务端运行的端口和前端请求的端口是否一致。
- 如果跨域,配置好跨域允许规则。
内容的提问来源于stack exchange,提问作者user2695433
相关产品推荐
相关产品推荐

