作者:程序员成长指北
原文:mp.weixin.qq.com/s/qsbidng1b...
大家好,今天咱们聊点有意思的:为什么你用 AI 聊天,有时候秒回,有时候却像"掉线"了一样半天没反应?其实,这背后有不少门道,尤其是服务端推送这招,能让你的 Web 应用体验大大提升!
为什么响应慢?大模型的"慢动作"
先来点背景知识。
现在的 AI 大模型,像 ChatGPT、Deepseek 这些,都是现点现做
---你问一句,它现场推理、现场生成答案,然后再把结果打包成 JSON,通过 HTTP 协议丢给前端。
问题来了:推理时间和你问的问题复杂度、生成的内容多少(token 数)直接挂钩。你要是问个你好
,AI 一秒就能回你。但你要它写一篇小说大纲,或者来个千字作文,AI 得「冥想」好一会儿。这时候,用户就只能干等着,体验很一般。
但你有没有发现,很多大模型的 Web 端其实响应很快?秘诀就是:流式(streaming
)传输!不用等答案全生成完,AI 生成一点就推一点,前端边收边展示,体验直接拉满!
什么是服务端推送?为啥它这么香?
服务端推送,顾名思义,就是服务器主动把消息"推"给你,而不是你一直去问有新消息吗
。这就像外卖小哥主动敲门送餐,而不是你每隔五分钟打电话问饭做好了吗
。
服务端推送的好处:
- 实时通知:新消息、活动提醒、外卖状态......都能第一时间送到你手上。
- 省资源:不用客户端一直"轮询"服务器,省流量、省算力,服务器也轻松。
- 体验好:还能给你推送个性化内容,比如专属优惠、直播提醒,用户粘性蹭蹭涨!
常见场景有:微信消息、新闻推送、外卖进度......你手机上各种推送,基本都靠这套
常见的实时通信方案大盘点
传统轮询 & 长轮询
- 轮询 :客户端定时问
有新消息吗?
,服务器回有/没有
。实现简单,但延迟高、资源消耗大。 - 长轮询 :升级版。客户端问一次,服务器没新消息就
憋着
,有了再回。减少了请求次数,但还是有延迟。
HTML5 新玩法:WebSocket & SSE
- WebSocket:双向实时通信,适合互动性强的场景,比如在线聊天、游戏。
- SSE:服务端单向推送,适合消息通知、进度更新等场景,简单易用。
特性 | SSE(Server-Sent Events) | WebSocket |
---|---|---|
协议 | HTTP | TCP |
通信方向 | 单向(服务端→客户端) | 双向 |
实现复杂度 | 简单 | 稍复杂 |
自动重连 | 内置 | 需手动实现 |
数据格式 | 文本/二进制 | 类型广泛 |
事件支持 | 支持自定义事件 | 不支持 |
连接数限制 | 有(HTTP/1.1 6个) | 基本无限制 |
浏览器支持 | 主流支持,IE不行 | 主流都支持 |
第三方推送服务
常见的有操作系统提供相应的推送服务,如苹果的APNs(Apple Push Notification service)、谷歌的FCM(Firebase Cloud Messaging)等。同时,也有一些跨平台的推送服务,如个推、极光推送、友盟推送等,帮助开发者在不同平台上实现统一的推送功能。
这种推送方式在生活中十分常见,一般你打开手机就能看到各种信息推送,基本就是利用第三方推送来实现。
SSE
SSE(Server-Sent Events)就是服务端推送的「轻骑兵」,基于 HTTP 协议,部署简单,特别适合服务器主动推消息,客户端只需接收的场景。

EventSource:用起来超简单
SSE 在前端的入口
就是 EventSource
。
EventSource 接受两个参数:URL 和 options。
URL
:就是服务器发流的地址,写上它,浏览器立刻自动给你搭通道,一有消息就往下传。options
(可选参数):里边有个withCredentials
,决定要不要带上 cookie、HTTP 认证啥的。默认是 false,就是不带,如果想带就设置成 true。
你只需要几行代码,就能和服务器建立实时通道:
javascript
const eventSource = new EventSource('http_api_url', { withCredentials: true });
// 监听连接开启
eventSource.addEventListener('open', event => {
console.log('连接已开启');
});
// 监听消息
eventSource.addEventListener('message', event => {
console.log('收到消息:', event.data);
});
// 监听自定义事件
eventSource.addEventListener('myEvent', event => {
console.log('收到自定义事件:', event.data);
});
// 监听错误
eventSource.addEventListener('error', event => {
console.log('出错啦:', event);
});
// 关闭连接
eventSource.close();
是不是很简单?而且还能自动重连,断了也不怕!
Stream API:数据流处理更灵活
Stream API 让你可以像流水线一样处理网络数据,把大文件、长内容分块处理,边下边用,效率高还不卡顿。


@microsoft/fetch-event-source
虽然浏览器自带的 EventSource 很好用,但有些场景它就有点「力不从心」了,比如:
- 不能带请求体(body),只能 GET,不能自定义请求头
- 断线重连策略不可控
- 只能用浏览器原生实现
这时候,@microsoft/fetch-event-source
就派上用场了!它基于 Fetch API,支持各种请求方式、请求头、请求体,还能自定义重试策略,灵活到飞起!
用法示例:
javascript
import { fetchEventSource } from"@microsoft/fetch-event-source";
const controller = new AbortController();
fetchEventSource("https://demo.com/chat", {
method: "POST",
body: JSON.stringify({ message: "你好,AI!" }),
headers: { "Content-Type": "application/json" },
signal: controller.signal,
onopen(response) {
// 连接已建立
},
onmessage(msg) {
console.log("收到消息:", msg.data);
},
onclose() {
console.log("连接关闭");
},
onerror(err) {
controller.abort();
console.error("出错啦:", err);
}
})
AbortController:优雅地中断请求
有时候,用户点了取消
或者页面跳转了,咱们就得把还在进行的网络请求停掉。这时候,AbortController 就是你的好帮手!
用法:
ini
const controller = new AbortController();
const signal = controller.signal;
fetch(url, { signal })
.then(response => { /* 处理响应 */ })
.catch(error => {
if (error.name === 'AbortError') {
console.log('请求被取消');
} else {
// 其他错误
}
});
// 需要取消时
controller.abort();
现在你知道了吧?想让你的 Web 应用秒回
,服务端推送(尤其是 SSE)绝对是个好选择!不管是消息通知、AI 聊天、进度更新,体验都能大大提升。赶紧试试吧,让你的产品快人一步!