透過 SSE 串流傳送回應¶
本導覽會追蹤聊天回應從 ASP.NET Core API 傳送至 Blazor WebAssembly 瀏覽器用戶端的過程。您將瞭解確切的 SSE 線路格式、排清的重要性,以及用戶端如何剖析串流區塊。
API 進入點¶
ChatController.StreamChat
會處理 POST /api/chat/stream。它接受 ChatRequest,選擇要求的模型,若未指定則使用 claude-haiku-4.5 預設值,並將回應設定為伺服器傳送事件:
Response.ContentType = "text/event-stream";
Response.Headers.CacheControl = "no-cache";
Response.Headers.Connection = "keep-alive";
這些標頭會告知中介系統與瀏覽器,這是長時間存續的串流,而不是應緩衝至完成後才傳送的一般 JSON 回應。
線路格式¶
對於
CopilotChatService.ChatStreamAsync 產生的每個區塊,控制器會序列化一個小型 JSON 物件,並寫入一則 SSE 訊息:
串流正常完成時,端點會寫入結束標記:
如果串流開始後發生例外狀況,控制器會在相同的 SSE 資料通道中寫入錯誤事件:
此時已無法可靠地改用 HTTP 錯誤狀態。狀態碼與回應標頭都已送出,因此若後期發生失敗,唯一實用的回報方式是在串流承載資料中傳送。
排清每個區塊¶
每個內容區塊之後, ChatController.StreamChat 都會排清回應本文:
await Response.WriteAsync($"data: {data}\n\n", cancellationToken);
await Response.Body.FlushAsync(cancellationToken);
如果沒有 FlushAsync,伺服器、主機、Proxy 或瀏覽器可能會緩衝資料。SDK 可能正確產生增量內容,但使用者在緩衝區填滿或要求結束前都看不到任何內容,因而誤以為串流功能失效。
取消¶
StreamChat 接受要求 CancellationToken (由 ASP.NET Core 提供)。控制器會將它傳入 CopilotChatService.ChatStreamAsync,檢查
IsCancellationRequested ,並在迴圈期間同時將其傳遞至 WriteAsync 以及
FlushAsync。如果瀏覽器分頁關閉或要求遭放棄,API 便有途徑停止寫入並結束串流工作。
瀏覽器用戶端¶
Blazor 用戶端程式碼位於
ChatService.StreamChatAsync。它會將 POST 要求傳送至 /api/chat/stream ,並搭配 HttpCompletionOption.ResponseHeadersRead:
ResponseHeadersRead 很重要,因為它會在回應標頭抵達後立即回傳。用戶端接著能逐行讀取本文串流,而不必等待完整回應。
剖析器會忽略空白行、尋找 data: 前置字串,並在遇到下列內容時停止: [DONE],並剖析 JSON 資料事件。 content 值會產生至 UI; error
值會轉換為例外狀況。
零售分析系統提示詞¶
ChatService.StreamChatAsync 會在呼叫端未提供系統訊息時傳送預設訊息。該提示詞會將助理定位為雜貨零售商的零售分析助理、提供示範內容,並要求使用 Markdown 表格與項目符號,根據資料提出商業洞察。它也會指示助理不要修改程式碼或建議程式碼變更。
Home.razor
會將使用者的提示詞與選取的模型傳遞至 ChatService.StreamChatAsync。因此,在要求送達 API 前,用戶端服務會套用預設系統提示詞。
使用 curl 試用¶
請將要求指向本機 API 使用的連接埠。例如,如果 API 正在 Web 用戶端的預設 API 基底位址上接聽,請使用下列命令傳送串流要求: curl -N ,讓 curl 不會緩衝回應:
curl -N -X POST http://localhost:5050/api/chat/stream \
-H "Content-Type: application/json" \
-d '{
"prompt": "Summarise customer C003 and recommend a segment.",
"model": "claude-haiku-4.5",
"systemMessage": "You are a retail analytics assistant."
}'
您應該會看到多則 data: {"content":"..."} 訊息,後接
data: [DONE]。