Roy-Try-Catch
← Back to list

【RealTime】Server-Sent Events - php 範例

Roy • Updated 2026-10-15 15:38:43

Server-Sent Events (SSE) 是一種讓伺服器以即時串流的方式,將更新或事件推送到客戶端的技術。與 WebSocket 不同,SSE 是單向的,只支援從伺服器向客戶端推送資料串流,因此很適合用在需要即時更新資料的情境,例如即時通知、資料串流等。本文將介紹如何在 Laravel 框架中實作 SSE。

什麼是 Server-Sent Events (SSE)?

SSE 是基於 HTTP 協定的單向資料串流技術。它讓伺服器能在與客戶端建立的持久連線上,持續把事件推送給客戶端。客戶端只需使用標準的 JavaScript API 就能接收這些事件,因此 SSE 很容易使用與整合。

示意圖:

sse example

以下範例是在 Laravel 框架中撰寫,用來即時顯示股票資料串流:

public function sseExample()
{
    // 如果輸出緩衝級別大於0,清空並關閉輸出緩衝區
    if (ob_get_level() > 0) {
        ob_end_clean();
    }

    // 禁用輸出緩衝和壓縮
    ini_set('output_buffering', 'off');
    ini_set('zlib.output_compression', false);

    // 設定 SSE 所需的 HTTP 標頭
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');
    header('Connection: keep-alive');
    header('X-Accel-Buffering: no'); // 防止 Nginx 緩衝 SSE 輸出

    // 如果沒有緩衝級別,啟動輸出緩衝
    if (ob_get_level() == 0) {
        ob_start();
    }

    // 返回一個流式響應,用於 SSE
    return response()->stream(function () {
        while (true) {
            // 獲取即時庫存數據
            $stocks = $this->getInventory();

            // 將數據以 SSE 格式發送到客戶端
            echo "data: " . json_encode([
                'stocks' => $stocks,
                'timestamp' => now()->toIso8601String(), // 當前時間的 ISO 8601 格式
            ]) . "

            "; // SSE 格式要求以雙換行結束每條消息

            // 如果有緩衝內容,將其發送到客戶端
            if (ob_get_length() > 0) {
                ob_end_flush(); // 發送當前的緩衝區內容並關閉輸出緩衝
            }
            flush(); // 刷新輸出緩衝

            // 檢查連接是否中斷,若中斷則記錄錯誤日誌並退出循環
            if (connection_aborted()) {
                error_log("SSE: Connection aborted");
                break;
            }

            // 如果沒有緩衝級別,重新啟動輸出緩衝
            if (ob_get_level() == 0) {
                ob_start();
            }

            // 等待1秒鐘後再發送下一條消息
            sleep(1);
        }
    }, 200, [
        'Content-Type' => 'text/event-stream', // 設定 SSE 的內容類型
        'Cache-Control' => 'no-cache', // 禁止緩存
        'Connection' => 'keep-alive', // 保持連接
        'X-Accel-Buffering' => 'no', // 防止 Nginx 緩衝 SSE 輸出
        'Access-Control-Allow-Origin' => '*', // 允許跨域訪問
    ]);
}

延伸閱讀

Comments

No comments yet.

請先登入