一篇文章说明清楚Web 实时消息推送的几种方式
Web 实时消息推送详解
消息推送概述
消息推送是指服务器主动向客户端发送通知,用于吸引用户关注某些事件。分为 Web 端消息推送 和 移动端消息推送。
实现目标:触发某个事件后,Web 页面通知数字实时更新。
两种消息获取方式
拉取(Pull):客户端定时请求服务器。
推送(Push):服务器主动推送消息。
实现方案总结
1. 短轮询 (Short Polling)
机制:客户端定时向服务器发起请求,服务器实时返回数据。
优点:
简单易实现。
缺点:
频繁请求导致资源浪费。
示例代码:
setInterval(() => {
messageCount().then((res) => {
if (res.code === 200) {
this.messageCount = res.data;
}
});
}, 1000);
2. 长轮询 (Long Polling)
机制:服务端在有数据更新时才响应客户端请求,超时后客户端再发起新的请求。
优点:
减少无效请求。
缺点:
挂起请求会浪费资源。
示例代码:
@Controller
@RequestMapping("/polling")
public class PollingController {
@GetMapping("watch/{id}")
@ResponseBody
public DeferredResult<String> watch(@PathVariable String id) {
DeferredResult<String> deferredResult = new DeferredResult<>(TIME_OUT);
watchRequests.put(id, deferredResult);
return deferredResult;
}
@GetMapping("publish/{id}")
@ResponseBody
public String publish(@PathVariable String id) {
watchRequests.get(id).forEach(d -> d.setResult("更新"));
return "success";
}
}
3. iframe 流
机制:隐藏的 <iframe>
标签通过持续连接服务器实现实时推送。
优点:
实现简单。
缺点:
浏览器兼容性差,服务器开销高。
示例代码:
<iframe src="/iframe/message" style="display:none"></iframe>
@Controller
@RequestMapping("/iframe")
public class IframeController {
@GetMapping(path = "message")
public void message(HttpServletResponse response) throws IOException, InterruptedException {
while (true) {
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-cache,no-store");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().print(" <script type=\"text/javascript\">\n" +
"parent.document.getElementById('clock').innerHTML = \"" + count.get() + "\";" +
"parent.document.getElementById('count').innerHTML = \"" + count.get() + "\";" +
"</script>");
}
}
}
4. SSE (Server-Sent Events)
机制:基于 HTTP 协议,服务端单向推送事件到客户端。
优点:
简单易用,支持自动断线重连。
缺点:
不支持双向通信。
具体的详细说明可以查看我的另一篇文章
示例代码:
let source = new EventSource('/sse/sub/7777');
source.onmessage = (e) => console.log(e.data);
服务端代码:
public static SseEmitter connect(String userId) {
SseEmitter sseEmitter = new SseEmitter(0L);
sseEmitterMap.put(userId, sseEmitter);
return sseEmitter;
}
5. WebSocket
机制:基于 TCP,实现客户端和服务端的双向通信。
优点:
全双工通信,性能优异。
缺点:
实现复杂。
示例代码:
let ws = new WebSocket('ws://localhost:7777/webSocket/10086');
ws.onmessage = (data) => console.log(data);
服务端代码:
@ServerEndpoint("/websocket/{userId}")
public class WebSocketServer {
@OnOpen
public void onOpen(Session session) {
this.session = session;
}
@OnMessage
public void onMessage(String message) {
System.out.println(message);
}
}
6. MQTT
机制:基于发布/订阅模式的轻量级通信协议,适合物联网环境。
优点:
轻量稳定,适合资源受限的场景。
缺点:
实现复杂。
方案对比
推荐:
使用 SSE 处理单向推送需求,如站内信。
使用 WebSocket 处理双向通信需求,如实时聊天。
在物联网场景中使用 MQTT。
License:
CC BY 4.0