被低估的服务器发送事件(SSE)

大多数开发者都知道WebSocket,但服务器发送事件(SSE)提供了一个更简单、常被忽视的替代方案,值得更多关注。让我们探讨为什么这项技术被低估,以及它如何使你的应用受益。

什么是服务器发送事件?

SSE通过HTTP建立了一个从服务器到客户端的单向通信通道。与WebSocket的双向连接不同,SSE保持一个开放的HTTP连接以进行更新。可以将其视为广播电台:服务器传输,客户端监听。

为什么它被低估?

两个主要因素导致了SSE的低估:

  1. WebSocket的流行:WebSocket的全双工通信能力掩盖了SSE。
  2. 感知限制:单向特性可能看起来有限制,但实际上对于许多用例来说已经足够。

SSE的关键优势

实现简单

SSE利用标准的HTTP协议,消除了WebSocket连接的复杂性。

基础设施兼容性

SSE与现有的HTTP基础设施无缝协作:

  • 负载均衡器
  • 代理
  • 防火墙
  • 标准HTTP服务器

资源效率

与WebSocket相比,资源消耗更低,因为:

  • 单向特性
  • 使用标准HTTP连接
  • 不需要维护持久的套接字

自动重连

浏览器内置支持:

  • 处理连接中断
  • 自动重连尝试
  • 提供弹性的实时体验

清晰的语义

单向通信模式强制:

  • 明确的职责分离
  • 简单的数据流
  • 简化的应用逻辑

实际应用场景

SSE在以下场景中表现出色:

  1. 实时新闻流和社交更新
  2. 股票行情和金融数据
  3. 进度条和任务监控
  4. 服务器日志流
  5. 协作编辑(用于更新)
  6. 游戏排行榜
  7. 位置跟踪系统

实现示例

服务器端(Flask)

python 复制代码
from flask import Flask, Response, stream_with_context
import time
import random

app = Flask(__name__)

def generate_random_data():
    while True:
        data = f"data: Random value: {random.randint(1, 100)}\n\n"
        yield data
        time.sleep(1)

@app.route('/stream')
def stream():
    return Response(
        stream_with_context(generate_random_data()),
        mimetype='text/event-stream'
    )

if __name__ == '__main__':
    app.run(debug=True)

客户端(JavaScript)

python 复制代码
const eventSource = new EventSource("/stream");

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

eventSource.onerror = function(error) {
    console.error("SSE error:", error);
};

代码解释

服务器端组件:

  • /stream 路由处理SSE连接
  • generate_random_data() 持续生成事件
  • text/event-stream MIME类型标识SSE协议
  • stream_with_context 维护Flask应用上下文

客户端组件:

  • EventSource 对象管理SSE连接
  • onmessage 处理器处理传入事件
  • onerror 处理连接问题
  • 浏览器自动处理重连

限制和注意事项

在实现SSE时,请注意以下限制:

1. 单向通信

  • 仅支持服务器到客户端
  • 客户端到服务器的通信需要单独的HTTP请求

2. 浏览器支持

  • 在现代浏览器中支持良好
  • 可能需要为旧浏览器提供polyfill

3. 数据格式

  • 主要支持基于文本的数据
  • 二进制数据需要编码(例如,Base64)

4. 最好与HTTP/2配合使用

根据MDN文档:

警告:当不使用HTTP/2时,SSE受到最大打开连接数的限制,这在打开多个标签时尤其痛苦,因为每个浏览器的限制非常低(6)。这个问题在Chrome和Firefox中被标记为"不会修复"。这个限制是每个浏览器+域名的,这意味着你可以为www.example1.com打开6个SSE连接,为www.example2.com打开另外6个SSE连接(根据Stack Overflow)。当使用HTTP/2时,最大同时HTTP流的数量由服务器和客户端协商(默认为100)。

最佳实践

  1. 错误处理
python 复制代码
eventSource.onerror = function(error) {
    if (eventSource.readyState === EventSource.CLOSED) {
        console.log("Connection was closed");
    }
};
  1. 连接管理
python 复制代码
// 清理连接
function closeConnection() {
    eventSource.close();
}
  1. 重连策略
python 复制代码
let retryAttempts = 0;
const maxRetries = 5;

eventSource.onclose = function() {
    if (retryAttempts < maxRetries) {
        setTimeout(() => {
            // 重连逻辑
            retryAttempts++;
        }, 1000 * retryAttempts);
    }
};

实际示例:ChatGPT的实现

现代模型(LLMs)使用服务器发送事件(SSE)来流式传输响应。让我们探讨这些实现的工作原理及其独特之处。

通用模式

所有主要的LLM提供商都使用以下通用模式实现流式传输:

  • 返回 content-type: text/event-stream 标头
  • 流式传输数据块,块之间用 \r\n\r\n 分隔
  • 每个块包含一行 data: JSON

重要说明

虽然SSE通常与浏览器的EventSource API一起使用,但LLM不能直接使用它,因为:

  • EventSource仅支持GET请求
  • LLM API需要POST请求

OpenAI实现

基本请求结构

python 复制代码
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [{"role": "user", "content": "Hello, world?"}],
    "stream": true,
    "stream_options": {
      "include_usage": true
    }
  }'

响应格式

每个块的结构如下:

python 复制代码
"data":{
   "id":"chatcmpl-AiT7GQk8zzYSC0Q8UT1pzyRzwxBCN",
   "object":"chat.completion.chunk",
   "created":1735161718,
   "model":"gpt-4o-mini-2024-07-18",
   "system_fingerprint":"fp_0aa8d3e20b",
   "choices":[
      {
         "index":0,
         "delta":{
            "content":"!"
         },
         "logprobs":null,
         "finish_reason":null
      }
   ],
   "usage":null
}

"data":{
   "id":"chatcmpl-AiT7GQk8zzYSC0Q8UT1pzyRzwxBCN",
   "object":"chat.completion.chunk",
   "created":1735161718,
   "model":"gpt-4o-mini-2024-07-18",
   "system_fingerprint":"fp_0aa8d3e20b",
   "choices":[
      {
         "index":0,
         "delta":{

         },
         "logprobs":null,
         "finish_reason":"stop"
      }
   ],
   "usage":null
}

OpenAI返回的关键标头:

python 复制代码
HTTP/2 200
date: Wed, 25 Dec 2024 21:21:59 GMT
content-type: text/event-stream; charset=utf-8
access-control-expose-headers: X-Request-ID
openai-organization: user-esvzealexvl5nbzmxrismbwf
openai-processing-ms: 100
openai-version: 2020-10-01
x-ratelimit-limit-requests: 10000
x-ratelimit-limit-tokens: 200000
x-ratelimit-remaining-requests: 9999
x-ratelimit-remaining-tokens: 199978
x-ratelimit-reset-requests: 8.64s
x-ratelimit-reset-tokens: 6ms

实现细节

流式完成

流在以下情况下结束:

python 复制代码
data: [DONE]

使用信息

最终消息包括令牌使用情况:

python 复制代码
"data":{
   "id":"chatcmpl-AiT7GQk8zzYSC0Q8UT1pzyRzwxBCN",
   "object":"chat.completion.chunk",
   "created":1735161718,
   "model":"gpt-4o-mini-2024-07-18",
   "system_fingerprint":"fp_0aa8d3e20b",
   "choices":[

   ],
   "usage":{
      "prompt_tokens":11,
      "completion_tokens":18,
      "total_tokens":29,
      "prompt_tokens_details":{
         "cached_tokens":0,
         "audio_tokens":0
      },
      "completion_tokens_details":{
         "reasoning_tokens":0,
         "audio_tokens":0,
         "accepted_prediction_tokens":0,
         "rejected_prediction_tokens":0
      }
   }
}

结论

SSE为实时服务器到客户端通信提供了一个优雅的解决方案。它的简单性、效率以及与现有基础设施的集成使其成为许多应用的绝佳选择。虽然WebSocket在双向通信中仍然有价值,但SSE为单向数据流场景提供了更合适的解决方案。

原文:igorstechnoclub.com/server-sent...

相关推荐
mywpython19 分钟前
mac 最新的chrome版本配置selenium的方式
chrome·python·selenium·macos
闲人编程23 分钟前
形态学操作(腐蚀/膨胀/开闭运算)
python·opencv·图像识别
A_ugust__24 分钟前
vue3项目使用 python +flask 打包成桌面应用
开发语言·python·flask
软件测试曦曦25 分钟前
如何使用Python自动化测试工具Selenium进行网页自动化?
自动化测试·软件测试·python·功能测试·测试工具·程序人生·自动化
zidea36 分钟前
我和我的 AI Agent(1) 异步优先、结构化输出以及如何处理依赖
人工智能·python·trae
满怀10151 小时前
Python入门(5):异常处理
开发语言·python
莓事哒1 小时前
使用pytesseract和Cookie登录古诗文网~(python爬虫)
爬虫·python·pycharm·cookie·pytessarct
赵钰老师1 小时前
【Deepseek、ChatGPT】智能气候前沿:AI Agent结合机器学习与深度学习在全球气候变化驱动因素预测中的应用
人工智能·python·深度学习·机器学习·数据分析
独好紫罗兰2 小时前
洛谷题单3-P1980 [NOIP 2013 普及组] 计数问题-python-流程图重构
开发语言·python·算法
freejackman2 小时前
Selenium框架——Web自动化测试
python·selenium·测试