Server-Sent Events(SSE)了解

目录结构

1、Server-Sent Events(SSE)

2、EventSource的方法和属性

一、Server-Sent Events(SSE)

1、基本概念

Server-Sent Events(SSE)是一种基于 HTTP 的 服务器到客户端的单向实时通信技术,允许服务器主动向客户端推送数据。它通过持久的 HTTP 连接实现数据流的持续传输,适用于需要实时更新但无需客户端频繁发送数据的场景(如新闻推送、实时监控)。

SSE的简单模型:一个客户端去从服务端订阅一条“流”,之后服务器端可以发送消息给客户端直到服务端或客户端关闭该“流”,eventsource也称之为“server-sent-event"。EventSource接口是HTML5规范的一部分,允许Web页面通过标准HTTP连接接收服务器推送的数据。

2、核心特征

(1)单向通信

  • 客户端通过EventSource与服务器建立连接,但服务器只向客户端推送数据而客户端不能通过该连接发送数据

           在SSE(Server-Sent Events)中,“单向”指的是从服务器到客户端的数据流而不是客户端不断请求数据
           eg: 当存在新的消息、通知或动态数据时,服务器可主动推送到客户端不需要客户端不断发送请求(eg: 每隔一段时间轮询一次)
           客户端发送数据的方式:客户端通过普通的HTTP请求(eg: POST、GET)来和服务器交互,但和SSE连接本身无关
           客户端可向服务器发送数据,这个过程和SSE数据流(即从服务器推送到客户端的消息)是分开的

(2)基于HTTP

  • 使用标准的HTTP协议进行通信,通常用于服务器推送(Server-Sent Events, 简称SSE)
  • 数据以文本形式发送,通常是UTF8编码

(3)自动重连

  • 若连接中断,EventSource会自动重新连接,重试机制可通过设置【reconnect】时间间隔来调整

(4)简单文本协议

  • 从服务器发送的消息格式是文本类型,通常使用【{'Content-Type': 'text/event-stream'}】内容类型,每条消息是由多行组成并以特定格式传输

(5)浏览器原生支持

  • EventSource默认支持跨域,需要服务器在响应头中设置适当的CORS头(eg: Access-Control-Allow-Origin)

3、工作原理

客户端发起 SSE 请求 → 服务器保持连接 → 分块发送数据 → 客户端实时渲染 → 流结束或断开

(1)客户端发起请求

浏览器通过 EventSource API 向服务器发起一个 HTTP GET 请求,请求头包含 Accept: text/event-stream

request请求头

(2)服务器保持长连接

  服务器响应 HTTP 请求,设置以下响应头以启用 SSE:

  response响应头

(3)服务器推送数据流

服务器按 SSE 格式持续发送数据块,每条消息以 data: 开头,以两个换行符 \n\n 结尾:

实例展示如下(chunk数据一次有值一次空字符串交替输出)

data: {"id":"b580a71b-79c5-41a8-be6f-660ae59bbe47","object":"chat.completion.chunk","created":1743494669,"model":"deepseek-chat","system_fingerprint":"fp_3d5141a69a_prod0225","choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}]}

data: {"id":"b580a71b-79c5-41a8-be6f-660ae59bbe47","object":"chat.completion.chunk","created":1743494669,"model":"deepseek-chat","system_fingerprint":"fp_3d5141a69a_prod0225","choices":[{"index":0,"delta":{"content":"我是"},"logprobs":null,"finish_reason":null}]}

data: {"id":"2267107c-d69d-4e88-94b7-cb724410efd5","object":"chat.completion.chunk","created":1743495354,"model":"deepseek-chat","system_fingerprint":"fp_3d5141a69a_prod0225","choices":[{"index":0,"delta":{"content":"Deep"},"logprobs":null,"finish_reason":null}]}

(4)客户端接受并处理数据

浏览器通过 onmessage 或 addEventListener 监听数据:

接收数据进行处理展示

4、数据格式规范

SSE 数据流需遵循以下格式(每条消息可包含多个字段):

5、SSE通信过程

SSE通信过程,底层实现被浏览器给封装好包括数据的处理,流程如下

5、适用场景

6、优缺点对比

7、安全与性能建议

  • CORS 配置:确保服务器设置 Access-Control-Allow-Origin 头。

  • 频率控制:避免高频推送(如每秒数十次),防止客户端处理阻塞。

  • 身份验证:通过 Cookie 或 URL 参数传递 Token,或在 HTTP 头中添加 Authorization

  • 连接数限制:浏览器对同一域名下的 SSE 连接数有限制(通常 6 个),需合理设计。

8、与WebSocket区别

 

  • SSE
    • 单向通信:服务器通过已建立的连接将数据推送给客户端
    • 客户端不能通过SSE向服务器发送数据;eg: 客户端需要发送数据,但需要通过常规的HTTP请求(eg: POST)
  • WebSocket
    • 双向通信:客户端和服务器都可以在任何时候通过WebSocket连接发送数据
    • 这种方式适用于更复杂的实时交互场景(eg: 多人在线聊天),双方都可以实时通信

 

 

二、EventSource的方法和属性

EventSource() 构造函数:创建一个新的EventSource,从指定的URL接受服务器发送事件
 
----------- 实例属性 ---------- 从父接口EventTarget继承属性
从其父接口EventTarget继承属性
EventSource.readyState: 一个代表连接状态的数字:值是CONNECTING(0)、OPEN(1) 或 CLOSED(2)
EventSource.url: 一个表示事件源的URL字符串
EventSource.withCredentials: 一个布尔值,表示EventSource对象是否使用跨资源共享(CORS)凭据来实例化
 
----------- 实例方法 ----------- 从父接口EventTarget继承方法
EventSource.close(): 关闭连接(若存在)将readyState属性设置为CLOSED,若连接已关闭则该方法不执行任何操作
 
-------------- 事件 -------------
error: 在事件源连接未能打开时触发
message: 在事件源连接收到数据时触发
open: 在和事件源的连接打开时触发 (事件源本身可发送具有event字段的消息,将创建一个以该值为key的特定事件

创建一个EventSource实例
// 发送
startStream() {
  // 关闭旧连接(如果存在)
  if (this.eventSource) {
    this.eventSource.close();
  }
  this.icon = 'el-icon-loading'
  // 清空输出
  this.outputText = "";
  const message = this.queryParams.inputMessage
  const url = "http://localhost:18080/stream/streamData?message=" + message

  // 创建 EventSource 实例
  this.eventSource = new EventSource(url);

  // 连接打开时触发
  this.eventSource.onopen = () => {
    console.log(this.eventSource.readyState)
    console.log(this.eventSource.withCredentials)
  };

  // 监听消息事件
  this.eventSource.onmessage = (event) => {
    console.log(event)
    console.log("收到数据:", event.data)
    // 逐字追加文本
    this.appendText(event.data);
  };

  // 监听错误(连接发生错误或中断)
  this.eventSource.onerror = (error) => {
    console.error("SSE 错误:", error);
    this.eventSource.close();
    // 流数出结束更换按钮图标
    this.icon = 'el-icon-search'
  };
},
// 逐字追加文本(模拟打字机效果)
appendText(text) {
  let index = 0;
  const addChar = () => {
    if (index < text.length) {
      this.outputText += text.charAt(index);
      index++;
      addChar();
    }
  };
  addChar();
},
注意

EventSource每次收完消息,必须手动关闭evtSource.close(),才不会自动重新连接
自动重连是EventSource的特性之一,这个关闭的前提是服务器下发字段告诉客户端能够关闭才可以关闭

posted on 2025-04-02 11:29  天涯明月夜  阅读(1409)  评论(0)    收藏  举报