首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >websocket关闭指定原因

websocket关闭指定原因

作者头像
阿超
发布2024-12-13 09:30:59
发布2024-12-13 09:30:59
2.6K0
举报
文章被收录于专栏:快乐阿超快乐阿超

如果没有宽恕之心,生命会被无休止的仇恨和报复所支配。——阿萨吉奥

WebSocket 是一种轻量级、双向的实时通信协议,在现代 Web 应用中非常流行。它为客户端和服务端提供了长连接能力,适用于需要频繁数据交互的场景。然而,在实际开发中,我们经常需要处理 WebSocket 的关闭事件,而 关闭状态(CloseStatus) 是其中一个重要的概念,它能够帮助开发者理解连接关闭的原因,从而采取相应的措施。

什么是 CloseStatus?

在 WebSocket 协议中,每次连接关闭都会携带一个 关闭码(close code) 和可选的 关闭原因(reason phrase)。这些关闭码由 RFC 6455 定义,表示连接关闭的原因。例如:

  • 1000 (Normal Closure): 正常关闭,表示连接完成。
  • 1001 (Going Away): 客户端或服务端主动断开(例如页面关闭)。
  • 1002 (Protocol Error): 协议错误。
  • 1003 (Unsupported Data): 不支持的数据类型。

在 Spring Framework 中,org.springframework.web.socket.CloseStatus 提供了对这些状态的封装,便于我们处理 WebSocket 关闭事件。

12345678910

@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception { String deviceId = (String) session.getAttributes().get("deviceId"); if (deviceId == null || deviceId.isEmpty()) { session.close(CloseStatus.NOT_ACCEPTABLE.withReason("Missing deviceId")); return; } deviceSessionMap.put(deviceId, session); session.sendMessage(new TextMessage("连接成功,设备ID: " + deviceId));}

Spring WebSocket 中的 CloseStatus

Spring 提供了 CloseStatus 类来封装关闭码和原因。以下是 CloseStatus 的关键方法和属性:

  • getCode() 获取关闭码。
  • getReason() 获取关闭的原因(可能为空)。
  • 常量值: Spring 提供了常见关闭状态的预定义常量,例如 CloseStatus.NORMALCloseStatus.PROTOCOL_ERROR

123456789101112131415

// 使用 CloseStatus 处理关闭事件@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { System.out.println("WebSocket 连接已关闭"); System.out.println("关闭码: " + status.getCode()); System.out.println("关闭原因: " + status.getReason()); if (status.equals(CloseStatus.NORMAL)) { System.out.println("连接正常关闭"); } else if (status.getCode() == 1006) { // Abnormal closure System.out.println("连接异常关闭"); } else { System.out.println("关闭状态: " + status); }}

应用场景:处理不同的 CloseStatus

  1. 正常关闭 (1000) 适用于连接完成或用户主动断开。可以在关闭事件中释放资源、关闭相关线程或记录日志。
  2. 异常关闭 (1006) 常见于网络问题或客户端断开。可以设置重连机制来保持连接的稳定性。
  3. 协议错误 (1002) 当客户端发送了不符合协议的数据时,服务端可以选择断开连接。此时应在日志中记录详细信息,方便排查问题。
  4. 服务器繁忙 (1013) 如果服务端压力过大,可以选择发送此关闭状态,让客户端稍后重试。

12345

@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { System.err.println("WebSocket 传输错误: " + exception.getMessage()); session.close(CloseStatus.SERVER_ERROR);}

客户端处理关闭事件

在客户端中,我们也可以捕获 onclose 事件,并基于关闭状态码进行不同的操作。例如:

12345678910111213141516171819

const socket = new WebSocket("wss://example.com/socket");socket.onclose = (event) => { console.log(`WebSocket 关闭: 关闭码 ${event.code}, 原因: ${event.reason}`); if (event.code === 1000) { console.log("连接正常关闭"); } else if (event.code === 1006) { console.log("异常关闭,尝试重连..."); reconnect(); }};function reconnect() { setTimeout(() => { console.log("尝试重连..."); // 重新连接逻辑 }, 3000);}

常见问题与最佳实践

1. 为什么会收到 1006 状态?

1006 是由客户端生成的关闭码,通常用于无法与服务端正常通信的场景(例如网络中断)。建议在服务端日志中查看异常原因。

2. 如何向客户端发送自定义关闭状态?

Spring 提供了 WebSocketSession.close(CloseStatus) 方法,可以指定关闭码和原因。

1

session.close(new CloseStatus(4001, "自定义错误: Token 无效"));

客户端会在 onclose 事件中接收到此信息。

3. 如何避免意外关闭?

  • 定期发送心跳(ping/pong)以保持连接活跃。
  • 在连接关闭后实现自动重连。
  • 在关闭前提示用户保存未完成的数据。

状态码一览:

1000 - NORMAL

含义: 连接正常关闭,表明 WebSocket 通信已完成。

应用场景: 客户端或服务端主动关闭连接,释放资源。

示例:

1

session.close(CloseStatus.NORMAL);

1001 - GOING_AWAY

含义: 连接关闭是由于某一方离开,例如服务器关闭或浏览器跳转页面。

应用场景: 服务器维护期间关闭连接,或者用户关闭浏览器窗口。

示例:

1

session.close(CloseStatus.GOING_AWAY);

1002 - PROTOCOL_ERROR

含义: 由于协议错误而关闭连接。

应用场景: 客户端或服务端未遵循 WebSocket 协议(例如发送非法帧)。

示例:

1

session.close(CloseStatus.PROTOCOL_ERROR);

1003 - NOT_ACCEPTABLE

含义: 收到了无法处理的数据类型(例如服务端只接受文本,但收到了二进制消息)。

应用场景: 数据类型不匹配时关闭连接。

示例:

1

session.close(CloseStatus.NOT_ACCEPTABLE);

1005 - NO_STATUS_CODE

  • 含义: 未提供状态码的关闭,保留值。
  • 应用场景: 一般用于表示关闭帧中没有状态码,不能直接使用。

1006 - NO_CLOSE_FRAME

含义: 连接非正常关闭,例如未发送关闭帧。

应用场景: 网络中断、客户端或服务端崩溃等。

注意: 此状态码仅在客户端或工具中报告,不会出现在关闭帧中。

示例:

123

if (status.equals(CloseStatus.NO_CLOSE_FRAME)) { // 记录异常并尝试重连}

1007 - BAD_DATA

含义: 收到了与消息类型不一致的数据(例如,非 UTF-8 数据)。

应用场景: 数据格式验证失败时关闭连接。

示例:

1

session.close(CloseStatus.BAD_DATA);

1008 - POLICY_VIOLATION

含义: 收到的消息违反了服务器的策略。

应用场景: 服务器限制了某些操作或内容(例如,未授权访问)。

示例:

1

session.close(CloseStatus.POLICY_VIOLATION.withReason("Unauthorized access"));

1009 - TOO_BIG_TO_PROCESS

含义: 收到的消息太大,无法处理。

应用场景: 限制消息大小的服务器可能在超出限制时关闭连接。

示例:

1

session.close(CloseStatus.TOO_BIG_TO_PROCESS);

1010 - REQUIRED_EXTENSION

含义: 客户端期望服务器支持某些扩展,但服务器未提供。

应用场景: 客户端无法与服务器达成握手协议。

示例:

1

session.close(CloseStatus.REQUIRED_EXTENSION.withReason("Missing compression extension"));

1011 - SERVER_ERROR

含义: 服务器由于内部错误无法处理请求。

应用场景: 服务器发生未知异常时关闭连接。

示例:

1

session.close(CloseStatus.SERVER_ERROR.withReason("Unexpected internal error"));

1012 - SERVICE_RESTARTED

含义: 服务端正在重启,客户端可以稍后重连。

应用场景: 定期维护或部署新版本时关闭连接。

示例:

1

session.close(CloseStatus.SERVICE_RESTARTED);

1013 - SERVICE_OVERLOAD

含义: 服务端过载,建议客户端切换到其他服务器或稍后再试。

应用场景: 服务器资源不足时主动关闭连接。

示例:

1

session.close(CloseStatus.SERVICE_OVERLOAD);

1015 - TLS_HANDSHAKE_FAILURE

  • 含义: TLS 握手失败,保留值。
  • 应用场景: 用于标记安全连接建立失败的情况。

扩展状态码

4500 - SESSION_NOT_RELIABLE

含义: 会话变得不可靠,例如在超时发送消息时。

应用场景: 服务器检测到会话不稳定时可主动关闭连接。

示例:

1

session.close(CloseStatus.SESSION_NOT_RELIABLE);

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-12-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是 CloseStatus?
  • Spring WebSocket 中的 CloseStatus
  • 应用场景:处理不同的 CloseStatus
  • 客户端处理关闭事件
  • 常见问题与最佳实践
    • 1. 为什么会收到 1006 状态?
    • 2. 如何向客户端发送自定义关闭状态?
    • 3. 如何避免意外关闭?
  • 状态码一览:
    • 1000 - NORMAL
    • 1001 - GOING_AWAY
    • 1002 - PROTOCOL_ERROR
    • 1003 - NOT_ACCEPTABLE
    • 1005 - NO_STATUS_CODE
    • 1006 - NO_CLOSE_FRAME
    • 1007 - BAD_DATA
    • 1008 - POLICY_VIOLATION
    • 1009 - TOO_BIG_TO_PROCESS
    • 1010 - REQUIRED_EXTENSION
    • 1011 - SERVER_ERROR
    • 1012 - SERVICE_RESTARTED
    • 1013 - SERVICE_OVERLOAD
    • 1015 - TLS_HANDSHAKE_FAILURE
  • 扩展状态码
    • 4500 - SESSION_NOT_RELIABLE
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档