WebSocket 和 SSE 简单使用及区别

文章目录

  • [WebSocket 和 SSE 简单使用及区别](#WebSocket 和 SSE 简单使用及区别)
    • [1. SSE 是什么](#1. SSE 是什么)
    • [2. Spring Boot 中使用 SSE](#2. Spring Boot 中使用 SSE)
    • [3. SSE 适合哪些场景](#3. SSE 适合哪些场景)
    • [4. WebSocket 是什么](#4. WebSocket 是什么)
    • [5. Spring Boot 中使用 WebSocket](#5. Spring Boot 中使用 WebSocket)
    • [6. WebSocket 适合哪些场景](#6. WebSocket 适合哪些场景)
    • [7. WebSocket 和 SSE 的区别](#7. WebSocket 和 SSE 的区别)
    • [8. 怎么选择](#8. 怎么选择)
    • [9. 和 AI 流式输出的关系](#9. 和 AI 流式输出的关系)
    • [10. 总结](#10. 总结)

WebSocket 和 SSE 简单使用及区别

在 Web 开发中,HTTP 请求通常是"一问一答":客户端发起请求,服务端返回响应,请求就结束了。

但有些场景需要服务端主动把数据推给客户端,例如:

  • AI 流式回答
  • 消息通知
  • 聊天室
  • 实时日志
  • 订单状态变化
  • 大屏数据刷新

这类场景常见的方案有两个:WebSocket 和 SSE。

1. SSE 是什么

SSE 全称是 Server-Sent Events,意思是服务端发送事件。

它的特点是:客户端通过 HTTP 建立连接,服务端可以持续向客户端推送文本数据。

SSE 是单向通信:

text 复制代码
客户端  ----建立连接---->  服务端
客户端  <---持续推送----  服务端

也就是说,SSE 主要适合"服务端不断推消息给客户端"的场景。

2. Spring Boot 中使用 SSE

Spring MVC 中可以使用 SseEmitter 实现 SSE。

java 复制代码
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("/sse")
    public SseEmitter sse() {
        SseEmitter emitter = new SseEmitter(0L);

        new Thread(() -> {
            try {
                for (int i = 1; i <= 5; i++) {
                    emitter.send("第 " + i + " 条消息");
                    Thread.sleep(1000);
                }
                emitter.complete();
            } catch (Exception e) {
                emitter.completeWithError(e);
            }
        }).start();

        return emitter;
    }
}

前端可以这样接收:

html 复制代码
<!DOCTYPE html>
<html>
<body>
<div id="message"></div>

<script>
  const eventSource = new EventSource("/sse");

  eventSource.onmessage = function (event) {
    const div = document.getElementById("message");
    div.innerHTML += `<p>${event.data}</p>`;
  };

  eventSource.onerror = function () {
    eventSource.close();
  };
</script>
</body>
</html>

访问页面后,服务端会每隔一秒推送一条消息。

3. SSE 适合哪些场景

SSE 适合服务端向客户端单向推送数据:

  • AI 流式输出
  • 系统通知
  • 实时日志
  • 股票行情
  • 订单状态推送
  • 后台任务进度

比如 Spring AI 的流式输出,本质上就很适合配合 SSE 使用。服务端一边从大模型拿到生成内容,一边推给浏览器。

4. WebSocket 是什么

WebSocket 是一种双向通信协议。

建立连接后,客户端和服务端都可以主动给对方发消息。

text 复制代码
客户端  <----双向通信---->  服务端

WebSocket 更像是一条长期存在的通信通道,适合实时互动场景。

5. Spring Boot 中使用 WebSocket

先定义 WebSocket 处理器:

java 复制代码
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

@Component
public class MyWebSocketHandler extends TextWebSocketHandler {

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        session.sendMessage(new TextMessage("服务端收到:" + payload));
    }
}

再配置 WebSocket 路径:

java 复制代码
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 {

    private final MyWebSocketHandler myWebSocketHandler;

    public WebSocketConfig(MyWebSocketHandler myWebSocketHandler) {
        this.myWebSocketHandler = myWebSocketHandler;
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myWebSocketHandler, "/ws")
                .setAllowedOrigins("*");
    }
}

前端连接 WebSocket:

html 复制代码
<!DOCTYPE html>
<html>
<body>
<input id="text" placeholder="请输入消息">
<button onclick="send()">发送</button>
<div id="message"></div>

<script>
  const socket = new WebSocket("ws://localhost:8080/ws");

  socket.onmessage = function (event) {
    const div = document.getElementById("message");
    div.innerHTML += `<p>${event.data}</p>`;
  };

  function send() {
    const input = document.getElementById("text");
    socket.send(input.value);
    input.value = "";
  }
</script>
</body>
</html>

这样客户端可以主动发送消息给服务端,服务端也可以主动返回消息。

6. WebSocket 适合哪些场景

WebSocket 适合双向实时通信:

  • 在线聊天室
  • 在线客服
  • 多人协作编辑
  • 实时游戏
  • 实时控制台
  • 需要客户端和服务端频繁互发消息的业务

如果业务只是服务端推送进度或模型输出,用 SSE 更简单。如果业务需要用户和服务端实时互发消息,用 WebSocket 更合适。

7. WebSocket 和 SSE 的区别

对比项 SSE WebSocket
通信方向 服务端到客户端,单向推送 客户端和服务端双向通信
协议 基于 HTTP 独立的 WebSocket 协议
前端 API EventSource WebSocket
数据格式 主要是文本 文本和二进制都可以
自动重连 浏览器原生支持 需要自己实现
使用复杂度 较简单 相对复杂
适合场景 通知、日志、进度、AI 流式输出 聊天、协作、游戏、实时交互
浏览器支持 主流浏览器支持 主流浏览器支持

8. 怎么选择

如果只是服务端持续推送数据,优先考虑 SSE。

例如:

text 复制代码
服务端生成内容 -> 浏览器实时展示

这类场景使用 SSE 更简单。

如果客户端和服务端都需要频繁主动发送消息,选择 WebSocket。

例如:

text 复制代码
用户发送消息 -> 服务端处理 -> 服务端推送给其他用户

这类场景 WebSocket 更合适。

简单总结:

text 复制代码
只需要服务端推客户端:SSE
需要客户端和服务端双向通信:WebSocket

9. 和 AI 流式输出的关系

在 AI 应用中,用户输入一个问题后,大模型通常会一点一点生成内容。

这时常见流程是:

text 复制代码
用户提问
  ↓
后端调用大模型 stream 接口
  ↓
后端收到一段内容
  ↓
通过 SSE 推给前端
  ↓
前端逐字或逐段展示

如果使用 Spring AI,后端可能会返回 Flux<String>:

java 复制代码
@GetMapping(value = "/ai/stream", produces = "text/html;charset=UTF-8")
public Flux<String> stream(String msg) {
    return chatClient.prompt()
            .user(msg)
            .stream()
            .content();
}

这种写法就非常适合配合前端流式展示。

如果是完整的 AI 聊天室,而且需要用户在线状态、多人消息广播、主动取消生成、服务端主动控制会话等复杂能力,可以考虑 WebSocket。

10. 总结

SSE 和 WebSocket 都可以实现实时通信,但定位不一样。

SSE 更轻量,适合服务端单向推送,例如通知、进度、日志、AI 流式输出。

WebSocket 更灵活,适合双向通信,例如聊天室、在线客服、协作编辑、实时游戏。

实际开发中,不需要一上来就用最复杂的方案。能用普通 HTTP 解决就用 HTTP;需要服务端推送就考虑 SSE;需要双向实时通信再使用 WebSocket。

相关推荐
虎头金猫6 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
只睡四小时6 天前
Canvas 弹道联机实战:700 行 + 固定时间步长
python·websocket·html5·游戏开发·canvas
wuyk5556 天前
《WiFi 嵌入式物联网开发全套实战》| 第 16 章 ESP32 AP+STA 双模共存原理与工程坑点
网络·stm32·物联网
XUEYUAN52126 天前
ASN 自治系统号风控:平台如何通过 IP 所属自治域批量识别代理流量
python·网络协议·http·网络安全·socks5
QYRdata6 天前
年均增速24.2%!机器人数据湖未来六年增长动能强劲
网络·机器人·服务发现
CHENKONG_CK6 天前
破解制鞋打磨痛点:RFID赋能去毛刺工序自动化升级
网络·单片机·嵌入式硬件·网络协议·tcp/ip
chshang19926 天前
工业路由器是什么?浅谈5G工业网络中的IR602
网络·物联网·5g·智能路由器
萧瑟余晖6 天前
Netty 核心组件与 Reactor 模型详解
网络·架构
ITxiaobing20236 天前
IP 定位服务选型指南:从准确率到工程落地的技术考察
linux·服务器·网络
wuyk5556 天前
【Socket 进阶之路】第 9 章 Linux 网络服务量产稳定性优化|心跳保活、TIME_WAIT、SO_LINGER、内存池、断线重连、完整异常防护框架
linux·服务器·开发语言·网络·物联网