springboot 中使用 websocket

第一步:开启websocket

java 复制代码
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // 其他 WebSocket 处理器的注册(可选)
    }
 
    // 关键:注册 @ServerEndpoint 注解的类
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

第二步:编写具体的处理逻辑

java 复制代码
@ServerEndpoint("/anno/myMsg/{tenantId}/{principal}")     //前端请求 这个地址,即可建立 websocket 链接
@Component
@Slf4j
public class TestEndpoint {
 
    @OnOpen
    public void onOpen(Session session) {       //连接建立之后,做什么
        log.info("连接成功");
        WebSocketObserver observer = new WebSocketObserver(session);
        // get subject
        WebSocketSubject subject = WebSocketSubject.Holder.getSubject(session.getId());
        // register observer into subject
        subject.addObserver(observer);
    }
 
    @OnClose                             //链接关闭的时候,做什么
    public void onClose(Session session) {  
        log.info("连接关闭");
        // get subject
        WebSocketSubject subject = WebSocketSubject.Holder.getSubject(session.getId());
 
        // get observer
        WebSocketObserver observer = new WebSocketObserver(session);
        // delete observer from subject
        subject.deleteObserver(observer);
 
        // close session and close Web Socket connection
        try {
            if (session.isOpen()) {
                session.close();
            }
        } catch (IOException e) {
            throw new RuntimeException("close web socket session error.", e);
        }
    }
 
    @OnMessage              //接收到消息之后,怎么处理
    public String onMsg(@PathParam("principal") String principal, String text) {
        if (StrUtil.isEmpty(text)) {
            return "";
        }
        return "server 收到消息:" + text;
    }
 
    @OnError                //出现异常的时候,怎么处理
    public void onError(Session session, Throwable error) {
        log.info("连接error");
        throw new RuntimeException("web socket error.", error);
    }
}

就这两步即可在springboot中使用 websocket 。由于springboot 集成的 websocket 非常简洁,避免了去关心底层的 通道/套接字 等一系列东西,只需要关心业务即可




对websocket的加深理解

txt 复制代码
当前端想建立 websocket 请求的时候 会发送类似 ws://your-domain.com/anno/myMsg/1234/userAlice 这样的一个链接,那么这个链接就是一个单纯的 websocket 请求么?

Websocket 请求的本质

WebSocket 请求的链接(如 ws://your-domain.com/anno/myMsg/1234/userAlice)并非单纯的独立连接。WebSocket 协议在建立时需通过 HTTP 或 HTTPS 完成初始握手,之后才升级为双向通信的 WebSocket 连接。因此,WebSocket 与 HTTP 存在明确的关联性。

WebSocket 与 HTTP 的联系

WebSocket 连接的建立依赖 HTTP 的升级机制。客户端发送一个包含 Upgrade: websocketConnection: Upgrade 头部的 HTTP 请求,服务器响应状态码 101 Switching Protocols 后,协议升级为 WebSocket。此过程称为"握手"。

示例握手请求:

http 复制代码
GET /anno/myMsg/1234/userAlice HTTP/1.1
Host: your-domain.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

示例握手响应:

http 复制代码
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

WebSocket 链接的路径含义

路径 /anno/myMsg/1234/userAlice 通常由后端路由解析,用于标识通信频道或用户身份。例如:

  • /anno 可能表示通知服务模块。
  • myMsg/1234 可能标识特定消息或会话。
  • userAlice 可能用于区分客户端。

WebSocket 与 HTTP 的区别

通信模式

  • HTTP:无状态,单向(客户端请求-服务器响应)。
  • WebSocket:全双工,持久化连接,服务器可主动推送数据。

协议标识

  • HTTP 使用 http://https://
  • WebSocket 使用 ws://(明文)或 wss://(加密)。

性能对比

WebSocket 避免了 HTTP 的重复握手开销,适合实时应用(如聊天、游戏)。

实际应用中的关联案例

  1. 负载均衡

    WebSocket 连接可能经过 HTTP 反向代理(如 Nginx),需配置 proxy_set_header Upgrade $http_upgrade 等参数。

  2. 安全限制

    同源策略和 CORS 规则可能影响 WebSocket 连接,需处理与 HTTP 相同的安全策略。

  3. 身份验证

    初始握手阶段可通过 HTTP 头部(如 Authorization)传递身份令牌,与 REST API 共享鉴权逻辑。

总结

WebSocket 链接并非独立于 HTTP,其建立依赖于 HTTP 升级机制。路径设计由后端路由控制,用于业务逻辑区分。两者在协议层存在明确关联,但通信模式与性能特点截然不同。




全双工 半双工 单工

全双工

全双工通信允许双方同时发送和接收信息,就像日常打电话。通话时双方可以同时说话和听对方说话,无需等待对方结束。现代网络通信如视频通话也采用全双工模式,数据双向实时传输。

半双工

半双工通信中,双方可以互相发送信息,但不能同时进行。类似对讲机使用场景:按下通话键时只能说话,松开才能听对方回复。传统网络集线器(HUB)也属于半双工,同一时间只允许单向数据传输。

单工

单工通信仅允许单向信息传输,如广播、电视信号。听众只能接收内容,无法通过广播频道反向发送信息。键盘向电脑输入数据也是单工例子,信号仅从键盘流向主机。