2025.6.8

在 WebSocket 连接关闭前发送消息

是的,可以在 WebSocket 连接关闭前发送一条告别消息。以下是修改后的实现方式:

服务端修改 - Spring Boot WebSocket 处理器

import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

public class MyWebSocketHandler extends TextWebSocketHandler {

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("连接建立: " + session.getId());
        session.sendMessage(new TextMessage("欢迎连接到WebSocket服务器!"));
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String clientMessage = message.getPayload();
        System.out.println("收到消息: " + clientMessage);
        
        // 回复客户端
        String reply = "服务器已收到: " + clientMessage;
        session.sendMessage(new TextMessage(reply));
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, 
                                    org.springframework.web.socket.CloseStatus status) throws Exception {
        try {
            // 在连接关闭前发送告别消息
            if (session.isOpen()) {
                session.sendMessage(new TextMessage("感谢使用,再见!"));
                // 等待消息发送完成
                Thread.sleep(100); // 短暂延迟确保消息发送
            }
        } catch (Exception e) {
            System.err.println("发送告别消息时出错: " + e.getMessage());
        } finally {
            System.out.println("连接关闭: " + session.getId());
        }
    }
}

客户端修改 - HTML/JavaScript

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>WebSocket测试</title>
    <style>
        /* 样式保持不变 */
    </style>
</head>
<body>
    <!-- 其他HTML内容保持不变 -->

    <script>
        // ... 其他代码保持不变 ...

        // 连接关闭时
        socket.onclose = function(event) {
            addMessage("连接已关闭: " + event.reason);
        };

        // 添加一个手动关闭连接的按钮
        function closeConnection() {
            if (socket.readyState === WebSocket.OPEN) {
                // 先发送一条关闭前的消息
                socket.send("客户端准备关闭连接");
                // 然后优雅地关闭连接
                socket.close(1000, "客户端正常关闭");
            }
        }

        // 在页面上添加关闭按钮
        document.body.innerHTML += '<button onclick="closeConnection()">关闭连接</button>';
    </script>
</body>
</html>

关键点说明

  1. 服务端关闭前发送消息

    • afterConnectionClosed 方法中尝试发送告别消息
    • 使用 session.isOpen() 检查连接是否仍然可用
    • 添加短暂延迟确保消息发送完成
  2. 客户端优雅关闭

    • 先发送关闭通知消息
    • 使用 socket.close() 方法并指定状态码和原因
    • 状态码 1000 表示正常关闭
  3. 注意事项

    • 当连接正在关闭时,可能无法保证消息一定能送达
    • 对于重要消息,最好在关闭前提前发送
    • 生产环境中应考虑添加重试机制

更可靠的实现方式

如果需要在关闭连接前确保消息送达,可以这样修改:

@Override
public void afterConnectionClosed(WebSocketSession session, 
                                CloseStatus status) throws Exception {
    try {
        // 在关闭前发送消息
        String farewell = "感谢使用,再见!";
        session.sendMessage(new TextMessage(farewell));
        
        // 等待消息发送完成(最大等待时间)
        for (int i = 0; i < 5 && session.isOpen(); i++) {
            Thread.sleep(100);
        }
    } catch (Exception e) {
        System.err.println("发送告别消息时出错: " + e.getMessage());
    } finally {
        System.out.println("连接关闭: " + session.getId() + ", 原因: " + status.getReason());
    }
}

这样实现可以在连接关闭前尽可能确保告别消息被发送出去。

posted @ 2025-06-08 23:27  258333  阅读(20)  评论(0)    收藏  举报