WebSocket连接一建立就断开,需检查中间件注册顺序(AddWebSocket在UseRouting后、UseEndpoints前)和CORS配置(禁用*通配符,启用SupportsCredentials并指定具体域名)。

WebSocket连接一建立就断开?检查中间件注册顺序和CORS
ASP.NET Core里WebSocket不是“加了就行”,AddWebSocket必须在UseRouting之后、UseEndpoints之前调用,否则context.WebSockets.IsWebSocketRequest永远返回false。更隐蔽的问题是CORS——即使你设了options.AllowedOrigins.Add("*"),若前端跨域请求带了凭证(如cookie),*会直接被浏览器拒绝,得换成具体域名并配SupportsCredentials = true。
- 确保
ConfigureServices中调用services.AddWebSocket,且没漏掉services.AddControllers(哪怕不用MVC,它也影响路由管道) -
Configure方法里,app.UseWebSockets()必须出现在app.UseRouting()之后、app.UseEndpoints()之前 - 测试时先用
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" http://localhost:5000/ws直连,绕过浏览器CORS,确认服务端是否真能握手成功
SendAsync抛出“WebSocket is in an invalid state”?别在Receive循环外发消息
WebSocket对象是**非线程安全**的,_webSocket.SendAsync和_webSocket.ReceiveAsync不能并发调用。常见错误是:一个后台任务(比如定时器)想主动推数据,但此时客户端可能正卡在ReceiveAsync等待中,导致状态冲突。
- 所有发送操作必须包装进
lock或用ConcurrentQueue暂存,再由接收循环统一发出(参考WebSocketHandler类中_messages队列的设计) - 不要在
OnConnected里立刻SendAsync,等ReceiveAsync第一次返回后再发——握手完成前发数据,客户端可能收不到 - 发送前务必检查
_webSocket.State == WebSocketState.Open,关闭状态下硬发会抛异常
SSE比WebSocket简单?小心IIS和反向代理吞掉响应头
Server-Sent Events(SSE)用text/event-stream MIME类型+长连接,代码确实比WebSocket少一半,但部署时容易栽在基础设施上。IIS默认缓冲响应体,Response.Body写入后不Flush,客户端就一直等;Nginx默认超时60秒,连接空闲就断开。
- 服务端必须设置
Response.Headers["Cache-Control"] = "no-cache"、Response.Headers["Content-Type"] = "text/event-stream" - 每次写入后调用
await Response.Body.FlushAsync(),否则数据滞留在缓冲区 - Nginx需配置
proxy_buffering off;、proxy_read_timeout 3600;,IIS要关掉动态内容压缩(dynamicCompressionDisableTypes加text/event-stream)
该选WebSocket还是SSE?看客户端是否需要双向通信
如果只是服务器单向广播(如日志流、股价更新),SSE更轻量:HTTP协议、自动重连、支持EventSource原生API;但一旦要客户端发指令(如“暂停推送”、“切换数据源”),就必须WebSocket——SSE没有上行通道,强行用额外AJAX请求,就失去“单连接”的优势了。
- 移动端WebView兼容性:iOS Safari 12.2+才完整支持SSE,老版本只能退化为轮询;WebSocket在iOS 6+就稳定支持
- 连接数压力:SSE每个客户端占一个HTTP连接,高并发时不如WebSocket复用TCP连接省资源
- 调试难度:SSE的
EventSource在Chrome开发者工具Network面板里显示为pending,得切到Console看onerror事件;WebSocket有专门的WS标签页,帧级调试直观得多


















