出处:掘金
原作者:小old弟
2025 年 5 月 9 日,MCP(Model Context Protocol)迎来重磅升级—— Streamable HTTP 正式发布,取代了 HTTP SSE,成为 AI 模型通信的新标准!
前段搞了个 SSE,全都弃了,现在全是 Streamable HTTP,它是啥?为啥有全用这种协议,有什么好处,使得弃了前者,爱上后者
SSE (Server-Sent Events)
刚出来大模型 AI 的时候,SSE 这种协议各大网络平台全是它
SSE (Server-Sent Events):基于 HTTP 协议,浏览器从服务器接收持续数据更新的技术。客户端发起请求后,服务器可以不断向客户端“推送”信息,直到断开
sequenceDiagram participant c as 客户端(浏览器) participant s as 服务器 c ->> s: 请求 /sse s ->> c: 推送消息 data:xxx s ->> c: 推送消息 data:yyy s ->> c: 推送消息 data:zzz Note over s,c: 直到连接断开或页面关闭
特点:浏览器发起一次请求后,服务器不断地推送数据,自动保持连接
用 Node.js express 写的后端:
// sse-server.js
const express = require('express');
const app = express();
app.get('/sse', (req, res) => {
res.set({
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
let counter = 0;
const timer = setInterval(() => {
counter++;
res.write(`data: 第 ${counter} 条消息\n\n`);
if (counter >= 10) {
clearInterval(timer);
res.end(); // 关闭连接
}
}, 1000);
});
app.listen(3000, () => {
console.log('SSE 服务运行在 http://localhost:3000/sse');
});
后端响应格式:
HTTP/1.1 200 OK
Content-Type: text/event-stream
data: 这是第一条消息
data: 第二条消息来了
前端代码:
const source = new EventSource('/sse');
source.onmessage = (event) => {
console.log('收到消息:', event.data);
};
Streamable HTTP
Stream 流:在 HTTP 请求或响应过程中,内容像水流一样逐段发送,而不是等待全部内容生成完成再发。分块传输
sequenceDiagram participant c as 客户端(浏览器) participant s as 服务器 c ->> s: 请求 /stream s ->> c: 响应一部分(chunk 1) s ->> c: 响应一部分(chunk 2) s ->> c: 响应一部分(chunk 3) s ->> c: 响应完成
特点:服务器会一边处理一边发送内容,适用于大数据、长处理时间的场景
用 Node.js express 写的后端:
// stream-server.js
const express = require('express');
const app = express();
app.get('/stream', (req, res) => {
res.setHeader('Content-Type', 'text/plain');
res.setHeader('Transfer-Encoding', 'chunked');
let count = 0;
const timer = setInterval(() => {
count++;
res.write(`chunk #${count}\n`);
if (count >= 5) {
clearInterval(timer);
res.end('--- 结束 ---\n');
}
}, 1000);
});
app.listen(3001, () => {
console.log('Stream 服务运行在 http://localhost:3001/stream');
});
后端响应格式:
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
data: 这是第一条消息
data: 第二条消息来了
前端代码:
fetch('http://localhost:3001/stream')
.then(response => response.body.getReader())
.then(reader => {
const decoder = new TextDecoder();
return reader.read().then(function process({ done, value }) {
if (done) return;
console.log('流内容:', decoder.decode(value));
return reader.read().then(process);
});
});
MCP 服务器
MCP 服务器,在 stream 之前,有过 sse 和 stdio
- stdio 只局限于本地环境。做些简单的网络请求(如查询添加)、简单运算(加减乘除)这些,跟本地算力有关,不能用于企业级
- sse 单向推事件给客户端。有两种通信通道:HTTP 请求/响应,服务器推送事件:专门的
/sse
端点推送信息。但有缺点(关键问题):- 不支持断线重连/恢复:SSE 连接断开所有会话状态丢失,客户端必须重新建立连接并初始化整个会话
- 服务器需维护长连接:服务器必须为每个客户端维护一个长时间的 SSE 连接,大量并发用户会导致资源消耗剧增,当服务器重启或扩容时所有连接会中断影响用户体验和系统可靠性
- 服务器消息只能通过 SSE 传递:即使是简单的请求-响应交互、服务器也必须通过 SSE 通道返回信息,这就需要服务器一直保持 SSE 连接,造成不必要的复杂性和开销
- 基础设施兼容性限制:目前很多 Web 基础设施,如 CDN、负载均衡器、API 网关等,对长时间 SSE 连接支持性不够,企业防火墙有可能强制关闭超时 SSE 连接,造成连接不可用
在深入理解 Streamable HTTP 的设计原理后,我们再来看看它是如何解决 SSE (Server-Sent Events) 的四个关键问题的。这些问题的解决方式将帮助我们更透彻地掌握 Streamable HTTP 协议的优势
问题 1:不支持断线重连/恢复
SSE 在连接中断后,客户端需要重新建立连接并手动恢复数据流。而 Streamable HTTP 在每次通信时会记录唯一 ID,用于标识请求与响应对应关系。服务器和客户端均可存储这些 ID,从而实现自动断线重连与数据恢复,避免数据丢失或重复传输
# SSE 需要手动重连
client.connect() # 断开后需重新建立连接
# Streamable HTTP 自动恢复
response = client.request(id=last_id) # 使用 ID 续传
问题 2:服务器需维护长连接
SSE 依赖持久化长连接,导致服务器资源占用较高。而 Streamable HTTP 采用按需保持连接的策略:
- 传输过程中:保持连接以确保流式数据的完整性
- 传输结束后:服务器立即关闭连接,释放资源,避免不必要的开销
// SSE 保持长连接
const sse = new EventSource("/stream"); // 持久化连接
// Streamable HTTP 按需连接
fetch("/stream").then(stream => {
// 流结束自动关闭
});
问题 3:服务器消息只能通过 SSE 传递
SSE 强制使用 text/event-stream
格式,灵活性较低。Streamable HTTP 则支持动态响应模式:
- 普通 HTTP 响应:适用于简单请求(如一次性数据返回)
- SSE 流式响应:适用于实时数据推送(如日志流、金融行情)
服务器可根据场景智能切换模式,提高协议适用性
# SSE 强制使用 event-stream
GET /updates HTTP/1.1
Accept: text/event-stream
# Streamable HTTP 智能选择
GET /data HTTP/1.1
Accept: application/json or text/event-stream
问题 4:基础设施兼容性限制
SSE 在某些代理、CDN 或旧版网关中可能受限。而 Streamable HTTP 在设计时充分考虑了兼容性,确保能在各类网络设备、云服务及企业级架构中无缝运行,尤其适合 MCP(多云平台)等复杂环境
SSE 可能被代理拦截:
location /sse { proxy_set_header Connection ""; }
Streamable HTTP 标准 HTTP 兼容:
location /stream { proxy_pass http://backend; }
总结
- SSE 适用于服务器主动推送通知/事件的场景
- Streamable HTTP 适用于传输大内容、慢内容、流式内容的场景(如 ChatGPT 输出、视频、数据列表)