0
user-people-family-house-home

【RealTime】Server-Sent Events - php 範例

Server-Sent Events (SSE) 是一種允許服務器將更新或事件以實時流的形式推送到客戶端的技術。與 We...

Posted by Roy on 2024-08-29 22:38:11 Views

Server-Sent Events (SSE) 是一種允許服務器將更新或事件以實時流的形式推送到客戶端的技術。與 WebSocket 不同,SSE 是單向的,僅支持從服務器向客戶端的數據流推送。這使得 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 格式
            ]) . "\n\n"; // 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' => '*', // 允許跨域訪問
    ]);
}

View Comments