← 返回首页

基于 Spring Boot 的 WebSocket 实战:从握手到心跳的完整实现

本文介绍在 Spring Boot 中使用标准 WebSocket(javax.websocket)实现端到端通信,并补齐心跳与超时控制的关键细节。

1. 启用 WebSocket

在 Spring Boot 内嵌容器环境,注册 ServerEndpointExporter 即可扫描 @ServerEndpoint 标注的端点:

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Component
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

2. 定义端点与基本事件

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint("/ws")
public class WsEndpoint {
    private static final ConcurrentHashMap SESSIONS = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session) {
        SESSIONS.put(session.getId(), session);
        send(session, "{\\"type\\":\\"welcome\\"}");
    }

    @OnMessage
    public void onMessage(String msg, Session session) {
        // 根据自定义协议处理消息
        send(session, "{\\"type\\":\\"echo\\",\\"data\\":" + msg + "}");
    }

    @OnClose
    public void onClose(Session session) {
        SESSIONS.remove(session.getId());
    }

    @OnError
    public void onError(Session session, Throwable t) {
        t.printStackTrace();
    }

    private void send(Session s, String text) {
        try { s.getBasicRemote().sendText(text); } catch (Exception ignored) {}
    }
}

3. 心跳与超时

建议采用“应用层心跳”:客户端定期发送 ping,服务端回复 pong,并在服务端维护最近一次心跳时间戳,超时则主动关闭连接。

// 伪代码:处理心跳
if ("ping".equals(type)) {
    lastHeartbeat.put(sessionId, System.currentTimeMillis());
    send(session, "{\"type\":\"pong\"}");
}

同时在反向代理层(如 Nginx)提升超时阈值:

location /ws {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;
}

4. 协议建议

以上示例为教学用途,可按需拓展鉴权、路由与广播等能力。