首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

HTML5 Server-Sent Events (SSE) 實戰:Servlet 實現服務端推送與斷線重連

     編輯:Java 綜合教學

前言:為什麼選 SSE?

當需要「服務端 → 客戶端」單向實時推送(股價、通知、日誌流、進度條)時,SSE 是比 WebSocket 更輕量、更標準、自帶斷線重連的原生方案。本文完整演示:前端 EventSource API、後端 Servlet 實現、關鍵協議細節、生產級優化。

實時推送方案對比

方案連接模式雙向自動重連二進制適用場景
Short Polling短連接輪詢✅❌✅低實時性、簡單場景
Long Polling長連接掛起✅❌✅中實時性、兼容舊瀏覽器
SSE長連接流式❌ (單向)✅ 原生❌ (文本)服務端推送、日誌流、通知
WebSocket全雙工長連接✅❌ (需自行實現)✅雙向交互、IM、遊戲、協作編輯

前端核心:EventSource API

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>SSE 實時時間演示</title>
</head>
<body>
    Time: <span id="foo"></span><br><br>
    <button onclick="start()">Start</button>

    <script>
    function start() {
        // 1. 建立連接
        var eventSource = new EventSource("HelloServlet");

        // 2. 接收消息(文本數據)
        eventSource.onmessage = function(event) {
            document.getElementById("foo").innerHTML = event.data;
        };

        // 3. 錯誤處理(自動重連中斷時觸發)
        eventSource.onerror = function(err) {
            console.log("SSE error, browser will auto-reconnect", err);
        };

        // 4. 自定義事件類型(可選)
        // eventSource.addEventListener('customEvent', function(e) { ... });
    }
    </script>
</body>
</html>

EventSource 關鍵特性

  • 自動重連:瀏覽器原生支援,斷開後 ~2-3 秒自動重試,無需代碼干預
  • 單連接複用:一個 HTTP 連接持續接收多條事件
  • 文本協議:數據格式為 data: ...\n\n,不支援二進制
  • 跨域支援:需服務端設置 Access-Control-Allow-Origin

後端核心:Servlet 實現 SSE 協議

@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {

        // 1. 關鍵響應頭:聲明 SSE 內容類型
        resp.setContentType("text/event-stream");
        resp.setCharacterEncoding("UTF-8");
        // 2. 禁用緩衝,確保實時發送
        resp.setHeader("Cache-Control", "no-cache");
        resp.setHeader("Connection", "keep-alive");
        // 3. 跨域支援(按需)
        resp.setHeader("Access-Control-Allow-Origin", "*");

        PrintWriter writer = resp.getWriter();

        try {
            for (int i = 0; i < 10; i++) {
                // 4. SSE 協議格式:data: 內容\n\n(雙換行符結束)
                String data = "data: " + System.currentTimeMillis() + "\n\n";
                writer.write(data);
                writer.flush(); // 關鍵:強制刷新到網路
                Thread.sleep(1000); // 模擬業務間隔
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            writer.close();
        }
    }
}

SSE 協議格式詳解

data: 第一行消息內容
data: 第二行消息內容(多行用多個 data:)

\n\n  ← 空行分隔事件

event: customEvent  ← 自定義事件類型(可選)
data: {"key": "value"}  ← JSON 數據
id: 12345  ← 事件 ID,重連時瀏覽器發送 Last-Event-ID

\n\n

關鍵規則:

  • 每條事件以 雙換行符 \n\n 結束
  • data: 可多行,會拼接為單字符串(去掉末尾換行)
  • id: 允許斷點續傳,重連時瀏覽器發送 Last-Event-ID 請求頭
  • retry: 可指定重連間隔毫秒數

生產級優化清單

優化點方案
連接併發限制瀏覽器對同域名限制 6 個 SSE 連接(HTTP/1.1),HTTP/2 可突破
心跳保活服務端每 15-30 秒發送 :\n\n (註釋行) 防代理斷開
身份認證握手階段攜帶 Token 參數,或 Cookie 自動攜帶
負載均衡Sticky Session 或 Redis Pub/Sub 廣播消息到所有實例
壓力測試單實例支撐 ~10k 連接(依賴 Servlet 3.1 異步 Servlet)
異步 Servlet 支撐高併發使用 req.startAsync() 釋放容器線程

異步 Servlet 版本(支撐高併發)

@WebServlet(urlPatterns = "/AsyncSSE", asyncSupported = true)
public class AsyncSSEServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        resp.setContentType("text/event-stream");
        resp.setCharacterEncoding("UTF-8");
        resp.setHeader("Cache-Control", "no-cache");
        resp.setHeader("Connection", "keep-alive");

        final AsyncContext async = req.startAsync();
        async.setTimeout(0); // 無超時

        async.start(() -> {
            try (PrintWriter writer = resp.getWriter()) {
                for (int i = 0; i < 100; i++) {
                    writer.write("data: " + System.currentTimeMillis() + "\n\n");
                    writer.flush();
                    Thread.sleep(1000);
                }
            } catch (Exception e) {
                log.error("SSE error", e);
            } finally {
                async.complete();
            }
        });
    }
}

總結

SSE 以「原生自動重連、協議極簡、單向推送」三大優勢,成為服務端→客戶端實時流場景的最佳選擇。掌握 text/event-stream、data: ...\n\n、EventSource 三要素,配合異步 Servlet 與心跳保活,即可構建生產級推送服務。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved