服务器直接发送消息给客户端,核心答案是:使用WebSocket或SSE建立长连接,让服务器拥有主动推送能力,而不是依赖HTTP的请求-响应循环。
HTTP协议本身是“一问一答”的模式,客户端不开口,服务器就只能干等,要做实时推送,就得先建立一条“专线”,目前主流方案就两个:WebSocket和SSE,选哪个,取决于你要做双向聊天还是单向通知,下面我用人话拆开讲清楚。
服务器如何主动推送消息到客户端?先明白HTTP的局限
你每天打开网页,浏览器和服务器之间走的是HTTP协议,这个协议有个死规矩:客户端发请求,服务器给响应,没有请求,服务器哪怕有新鲜事也只能憋着。
早期为了解决“憋着”的问题,大家用过轮询,所谓轮询,就是客户端每隔几秒问一次“有消息了吗”,服务器被问烦了,但还得硬着头皮回,这叫“短轮询”,费流量、费带宽,还费服务器资源。
后来有了“长轮询”,客户端发一个请求,服务器先不急着回,等有消息了再回,如果等太久,客户端就再发一个,这确实比短轮询省点资源,但连接频繁断开重连,延迟依然存在,而且服务器要挂着一大堆挂起的请求,线程吃紧。
说白了,HTTP像一扇单向门,想实现服务器直接发消息给客户端,必须换一把双向钥匙,这就是WebSocket和SSE登场的理由。
服务器推送消息给客户端有哪些方案?WebSocket与SSE深度对比
严格说,服务器推送消息给客户端的技术方案不止两种,但真正能扛住生产环境压力、被行业共识认为最靠谱的,就是WebSocket和SSE,剩下的要么是过渡方案,要么是特定场景的补充。
WebSocket:真双向,适合聊天和协同
WebSocket是浏览器和服务器之间的一条全双工长连接,连接建立后,两边随时可以互发消息,没有“请求-响应”的束缚。
你用网页版钉钉聊天,对方发来一条消息,你的浏览器能立刻弹出小红点,这就是WebSocket的功劳,打工人一起编辑在线文档,你的光标移动能让同事实时看到,也是WebSocket在背后推数据。
WebSocket的优势很直白:
- 双向实时:服务器和客户端都能主动发数据,延迟低到毫秒级。
- 协议成熟:基于TCP,有完整的握手、心跳、断线重连的处理办法。
- 支持二进制:传图片、音频、视频流都没问题。
但它也有代价,WebSocket协议相对复杂,需要单独处理连接状态、心跳保活、断线重连逻辑,如果只是单向推送,有点杀鸡用牛刀。
SSE:轻量单向,适合通知和行情
SSE全称是Server-Sent Events,翻译过来就是“服务器发送事件”,它是基于HTTP的单向长连接,服务器可以持续往客户端推数据,但客户端不能通过这条连接反向发消息。
听起来好像很亏,但SSE自有它的位置,比如股票行情页面的价格跳动、后台系统的告警通知、日志的实时打出这些场景都是服务器单方面往客户端灌数据,不需要客户端回话。
SSE的优点很实在:
- 基于HTTP,无需额外协议,现有服务器基建都能兼容。
- 自带自动重连,连接断了,浏览器会自动重新发起连接,不用你写代码。
- 文本友好,直接推JSON字符串,简单直观。
缺点也明显:单向,不能发二进制大文件,而且浏览器对连接数有限制(每个域名一般是6个),但如果你只需要给客户端发消息,SSE反而是更省心的选择。
核心数据对比:WebSocket vs SSE
| 维度 | WebSocket | SSE |
|---|---|---|
| 连接方向 | 全双工(双向) | 半双工(仅服务器→客户端) |
| 协议基础 | 独立协议(ws/wss) | 基于HTTP(普通GET请求) |
| 自动重连 | 需自己实现 | 内置 |
| 二进制支持 | 支持 | 仅文本(可用Base64编码) |
| 复杂度 | 高 | 低 |
| 浏览器兼容性 | 现代浏览器普遍支持 | 大部分浏览器支持,IE除外 |
| 典型场景 | 聊天、在线游戏、协同编辑 | 通知、行情、日志流 |
WebSocket和SSE选哪个?实时推送场景对比
这是做实时功能时最纠结的问题,别急,按下面的思路选,基本不会错。
选型标准:先问自己三个问题
- 需要客户端回消息吗? 需要就选WebSocket,不需要则优先考虑SSE。
- 数据量多大? 频繁大量二进制数据,选WebSocket;纯文本推送,SSE足够。
- 运维成本能承受吗? 不想伺候复杂协议,SSE更省心。
比如你做一个客服系统,客户和客服要来回聊天,必须WebSocket,你做一个大屏展示机房温度,每隔几秒更新一次数据,SSE完全够用,何必上WebSocket。
实操:用Node.js几分钟搭一个WebSocket推送服务
很多人以为WebSocket多难,其实有现成库,以Node.js的ws库为例,核心代码就几行。
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
console.log('客户端连上了');
// 服务器主动给客户端发消息
ws.send('欢迎连接,我是服务器');
});
启动服务后,浏览器里用new WebSocket('ws://localhost:8080')就能连上,要定时推送,加个setInterval就行,注意生产环境要加心跳检测,防止连接被闲置切断。
实操:用Nginx配置SSE反向代理
SSE走的是普通HTTP长连接,但Nginx默认会缓冲响应,导致消息不能实时到达,所以配置上有两个关键点。
location /sse {
proxy_pass http://your_backend;
proxy_buffering off;
proxy_cache off;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
}
核心是proxy_buffering off;,关掉缓冲,让数据一到就转给客户端,前端用EventSource接口接收,代码更简单:
const source = new EventSource('/sse');
source.onmessage = (event) => {
console.log('收到服务器消息:', event.data);
};
实时消息推送服务器报价与成本考量
很多人搜“实时消息推送服务器报价”,其实这个价格没有固定数字,因为成本取决于你的并发量和数据量,小型业务,一台普通云服务器就能跑SSE,月成本可能只有几十到几百块,WebSocket因为要维持大量长连接,对内存和带宽要求更高,同配置下成本会更高一些。
更划算的做法是先用云厂商的托管服务,比如简米云的消息队列或酷番云的即时通信IM,它们按量计费,省去自己维护连接池的麻烦,据业内专家指出,相当一部分中小团队最终会选择托管服务,因为自建长连接服务的运维复杂度远超预期。
说实话,如果你只是做个内部通知工具,自建WebSocket加一台2核4G的服务器,跑几千个连接问题不大,但要做到全国范围的实时推送,还得考虑多地域部署、负载均衡、连接状态同步,这些才是真正的成本大头。
服务器直接发送消息给客户端常见问题
服务器推送消息到客户端,和普通HTTP请求有什么区别?
普通HTTP是客户端主动发起,服务器被动响应,服务器推送消息是服务器主动发起,客户端被动接收,这需要预先建立长连接,WebSocket或SSE就是干这个的。
SSE会自动重连吗?断线了怎么办?
SSE内置自动重连机制,连接断开后,浏览器会每隔几秒自动重新发起连接,并通过Last-Event-ID字段告诉服务器上次接收到了哪条消息,服务器可以续传遗漏的数据,WebSocket没有这个内置能力,需要自己写重连逻辑。
服务器推送消息用WebSocket还是SSE?能同时用吗?
可以同时用,一个页面里,聊天窗口用WebSocket,通知栏用SSE,互不干扰,但现代浏览器对每个域名的并发连接数有限制,SSE和WebSocket都会占用连接数,所以别开太多条,实际开发中,多数场景一条WebSocket或一条SSE就够用了。
结尾说回本质:服务器直接发送消息给客户端,不是某一种技术的专属能力,而是你对实时性需求的选择题,单向通知用SSE,双向互动用WebSocket,两者都能让服务器主动开口说话,选合适的那条路,比追最新技术更重要。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/554992.html




