【简单易懂】SSE 和 WebSocket(Java版)

一、前言

  • SSE(Server-Sent Events) 和 WebSocket 是两种用于实现实时通信的 Web 技术;
  • 但它们在设计、用途和实现方式上有显著区别。

二、SSE(Server-Sent Events)

  • 定义基于 HTTP 的单向通信协议,允许服务器主动向客户端推送数据

  • 特点

    • 单向通信:仅支持服务器 → 客户端的单向数据推送。
    • 基于 HTTP:使用简单,无需额外协议,兼容现有 HTTP 基础设施。
    • 自动重连:内置断线重连机制,客户端会自动尝试重新连接。
    • 轻量级:数据格式为纯文本(如 text/event-stream),适合推送简单数据,如新闻、股价。
  • 适用场景

    • 实时通知(如新闻、天气更新)。
    • 服务器主导的实时数据推送(如日志流、进度条更新)。
  • 局限性

    • 不支持客户端向服务器发送消息。
    • 部分旧浏览器(如 IE)不支持。

三、WebSocket

  • 定义基于 TCP 的全双工通信协议,支持客户端与服务器双向实时通信
  • 特点
    • 双向通信:客户端和服务端可以同时发送和接收数据。
    • 独立协议:通过 HTTP 升级握手建立连接(ws:// 或 wss://),之后脱离 HTTP 独立运行。
    • 低延迟:持久化连接,适合高频交互场景(如聊天、游戏)。
    • 支持二进制数据:可传输文本或二进制数据(如图片、音频)。
  • 适用场景
    • 实时聊天、协作工具。
    • 多人在线游戏、实时交易系统。
  • 局限性
    • 实现复杂度较高(需处理连接状态、心跳检测等)。
    • 需要服务器和客户端同时支持 WebSocket 协议。

四、核心区别对比

在这里插入图片描述


五、代码示例(基于Java的Spring Boot)

1、SSE

A.服务端代码
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

@RestController
public class SseController {

    @GetMapping(path = "/sse-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter streamEvents() {
        SseEmitter emitter = new SseEmitter(60_000L); // 超时时间 60 秒

        // 模拟实时数据推送(实际可能从数据库或外部服务获取)
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    SseEmitter.SseEventBuilder event = SseEmitter.event()
                            .data("SSE 数据 - " + i) // 推送的数据
                            .id(String.valueOf(i))   // 事件 ID(可选)
                            .name("sse-event");      // 事件名称(可选)
                    emitter.send(event);
                    Thread.sleep(1000); // 间隔 1 秒
                }
                emitter.complete(); // 完成推送
            } catch (Exception e) {
                emitter.completeWithError(e); // 异常处理
            }
        }).start();

        return emitter;
    }
}
B.客户端代码(JavaScript)
const eventSource = new EventSource('/sse-stream');
eventSource.onmessage = (e) => {
    console.log("收到 SSE 数据:", e.data);
};
eventSource.onerror = (e) => {
    console.error("SSE 连接错误:", e);
};
C.关键点
  • 服务端使用 SseEmitter 发送事件流。

  • 客户端通过 EventSource 监听数据。

2、WebSocket

A. [服务端]依赖引入(pom.xml)
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
B. [服务端]WebSocket配置类
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new MyWebSocketHandler(), "/ws")
                .setAllowedOrigins("*"); // 允许跨域
    }
}
C. [服务端]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 {
        // 连接建立时触发
        session.sendMessage(new TextMessage("服务端:连接成功!"));
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 收到客户端消息时触发
        String clientMsg = message.getPayload();
        System.out.println("收到客户端消息: " + clientMsg);

        // 回复客户端
        session.sendMessage(new TextMessage("服务端回复: " + clientMsg));
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
        // 连接关闭时触发
        System.out.println("WebSocket 连接关闭");
    }
}
D. 客户端测试(JavaScript)
const socket = new WebSocket('ws://localhost:8080/ws');

// 连接成功
socket.onopen = () => {
    console.log("WebSocket 连接已建立");
    socket.send("Hello WebSocket!");
};

// 接收消息
socket.onmessage = (e) => {
    console.log("收到消息:", e.data);
};

// 连接关闭
socket.onclose = () => {
    console.log("WebSocket 连接已关闭");
};
E.关键点
  • 服务端通过 WebSocketHandler 处理连接和消息
  • 客户端使用浏览器原生 WebSocket API 通信

六、使用建议 / 如何选择

  • 选择 SSE
    • 只需服务器向客户端推送数据(如实时通知、数据监控)。
    • 希望快速实现且兼容现有 HTTP 服务。
  • 选择 WebSocket
    • 需要双向实时交互(如聊天室、在线游戏)。
    • 对延迟敏感或需传输二进制数据。

七、总结

  • SSE 适合单向服务器推送场景,简单且对开发友好
  • WebSocket 适合双向高频通信,性能更优但实现复杂
  • 两者可结合使用(例如:用 SSE 接收通知,用 WebSocket 处理交互)。
  • 根据实际需求选择技术方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值