串流回應的正確實作:SSE 與中途中斷
串流不只是把字吐出來,還要處理中斷、錯誤與部分結果的保存。
串流讓使用者更早看到回應,但也讓錯誤處理變複雜——當你已經吐出一半內容時才發生錯誤,該怎麼辦。
伺服器端:SSE 格式
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no'); // 關掉 nginx 緩衝,否則會整包才送出
foreach ($chunks as $c) {
echo 'data: ' . json_encode(['delta' => $c], JSON_UNESCAPED_UNICODE) . "\n\n";
@ob_flush(); flush();
if (connection_aborted()) break; // 使用者關閉分頁就停止計費
}
echo "data: [DONE]\n\n";三個容易踩的坑
- 反向代理緩衝:nginx 預設會緩衝回應,串流會失效。要關掉
proxy_buffering。 - 沒偵測中斷:使用者關掉分頁後後端還在生成,白白付費。
- 錯誤發生在中途:已送出的內容無法收回,要用事件型別告知前端。
echo 'event: error' . "\n";
echo 'data: ' . json_encode(['message' => '生成中斷,請重試']) . "\n\n";部分結果要不要保存
取決於場景。長文生成建議保存並允許續寫;結構化輸出則不該保存部分結果——半個 JSON 沒有任何價值,直接標記失敗比較乾淨。
串流與結構化輸出不容易共存。需要 JSON 時,改成串流「進度訊息」而非內容本身,體驗一樣好但解析簡單得多。