ASP.NET Core 2 MVC中异常发生时关闭WebSocket并传递异常信息给客户端
在ASP.NET Core 2 MVC中处理WebSocket异常并通知客户端
我之前在做ASP.NET Core的WebSocket项目时也遇到过类似需求,下面是经过验证的实现方案,核心是通过try-catch包裹所有WebSocket相关逻辑,在异常发生时先向客户端发送错误信息,再优雅关闭连接。
步骤1:修改Startup.cs中的WebSocket中间件
首先在Configure方法的WebSocket中间件里添加异常捕获逻辑,确保连接建立和后续处理过程中的异常都能被处理:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // 保留你原有的其他中间件配置(比如UseStaticFiles、UseMvc等) app.Use(async (context, next) => { if (context.WebSockets.IsWebSocketRequest) { if (context.Request.Path == "/ws") { WebSocket webSocket = null; try { // 接受WebSocket连接 webSocket = await context.WebSockets.AcceptWebSocketAsync(); // 实例化自定义处理类 var webSocketHandler = new WebSocketConnectionHandler(webSocket); // 启动连接处理逻辑 await webSocketHandler.HandleConnectionAsync(); } catch (Exception ex) { // 异常处理:发送错误信息并关闭连接 if (webSocket != null && webSocket.State == WebSocketState.Open) { // 向客户端发送错误文本 var errorBytes = Encoding.UTF8.GetBytes($"服务器异常:{ex.Message}"); await webSocket.SendAsync( new ArraySegment<byte>(errorBytes), WebSocketMessageType.Text, endOfMessage: true, cancellationToken: CancellationToken.None); // 以错误状态码关闭连接,附带异常描述 await webSocket.CloseAsync( WebSocketCloseStatus.InternalServerError, $"错误详情:{ex.Message}", CancellationToken.None); } } finally { // 确保WebSocket资源被释放 webSocket?.Dispose(); } // 跳过后续中间件,因为WebSocket是长连接 return; } } // 非WebSocket请求,继续执行后续中间件 await next(); }); // 其他中间件配置... }
步骤2:在自定义处理类中添加异常捕获
你的自定义WebSocket处理类(比如WebSocketConnectionHandler)里的消息收发逻辑也需要包裹try-catch,避免单个消息处理异常导致整个连接意外断开:
public class WebSocketConnectionHandler { private readonly WebSocket _webSocket; private readonly byte[] _buffer = new byte[1024 * 4]; // 4KB接收缓冲区 public WebSocketConnectionHandler(WebSocket webSocket) { _webSocket = webSocket; } public async Task HandleConnectionAsync() { try { while (_webSocket.State == WebSocketState.Open) { // 接收客户端消息 var receiveResult = await _webSocket.ReceiveAsync( new ArraySegment<byte>(_buffer), CancellationToken.None); // 处理客户端消息的逻辑(这里替换成你的业务代码) var receivedMessage = Encoding.UTF8.GetString(_buffer, 0, receiveResult.Count); await ProcessReceivedMessageAsync(receivedMessage); // 如果客户端主动关闭连接,退出循环 if (receiveResult.CloseStatus.HasValue) { await _webSocket.CloseAsync( receiveResult.CloseStatus.Value, receiveResult.CloseStatusDescription, CancellationToken.None); } } } catch (Exception ex) { // 处理消息过程中的异常 if (_webSocket.State == WebSocketState.Open) { var errorBytes = Encoding.UTF8.GetBytes($"消息处理失败:{ex.Message}"); await _webSocket.SendAsync( new ArraySegment<byte>(errorBytes), WebSocketMessageType.Text, true, CancellationToken.None); // 根据异常类型选择合适的关闭状态码,比如InvalidPayloadData表示消息格式错误 await _webSocket.CloseAsync( WebSocketCloseStatus.InvalidPayloadData, ex.Message, CancellationToken.None); } } } // 示例:业务消息处理方法 private async Task ProcessReceivedMessageAsync(string message) { // 这里写你的业务逻辑,比如解析消息、操作数据库等 // 如果业务逻辑抛出异常,会被上层的try-catch捕获 if (string.IsNullOrEmpty(message)) { throw new ArgumentException("空消息不允许处理"); } // 其他处理逻辑... } }
关键注意事项
- 选择合适的关闭状态码:根据异常类型对应
WebSocketCloseStatus枚举值,比如:InternalServerError:服务器内部错误(比如数据库连接失败)InvalidPayloadData:客户端发送的消息格式错误PolicyViolation:违反业务规则(比如未授权操作)
- 确保连接状态有效:发送错误信息和关闭连接前,一定要检查
WebSocket.State是否为Open,避免触发新的异常 - 资源释放:通过
finally块确保WebSocket被正确释放,防止资源泄漏 - 跳过后续中间件:处理完WebSocket请求后要
return,不要调用next(),因为WebSocket是长连接,后续中间件不需要介入
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

