" />
文章

一篇文章说明清楚Web 实时消息推送的几种方式

Web 实时消息推送详解

消息推送概述

消息推送是指服务器主动向客户端发送通知,用于吸引用户关注某些事件。分为 Web 端消息推送移动端消息推送

实现目标:触发某个事件后,Web 页面通知数字实时更新。

两种消息获取方式

  1. 拉取(Pull):客户端定时请求服务器。

  2. 推送(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 协议,服务端单向推送事件到客户端。

优点

  • 简单易用,支持自动断线重连。

缺点

  • 不支持双向通信。

具体的详细说明可以查看我的另一篇文章

https://zhiwei.plus/archives/8a433f1d-7dd2-489d-8eee-d03a6e45ad70

示例代码

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

机制:基于发布/订阅模式的轻量级通信协议,适合物联网环境。

优点

  • 轻量稳定,适合资源受限的场景。

缺点

  • 实现复杂。


方案对比

方案

优点

缺点

短轮询

简单易实现

实时性差,资源浪费

长轮询

减少无效请求

资源浪费

iframe 流

实现简单

开销高,兼容性差

SSE

功能丰富,支持断线重连

不支持双向通信

WebSocket

性能高,支持双向通信

实现复杂,需额外配置

MQTT

轻量级,适合物联网

实现复杂,针对特定场景


推荐

  • 使用 SSE 处理单向推送需求,如站内信。

  • 使用 WebSocket 处理双向通信需求,如实时聊天。

  • 在物联网场景中使用 MQTT

License:  CC BY 4.0