You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.2 KiB

串流 JSON Lines

當你有一連串資料想以「串流」方式傳送時,可以使用 JSON Lines

/// info

在 FastAPI 0.134.0 新增。

///

什麼是串流?

Streaming」資料表示你的應用會在整個資料序列尚未完全準備好之前,就開始將資料項目傳送給用戶端。

也就是說,它會先送出第一個項目,用戶端接收並開始處理時,你的應用可能仍在產生下一個項目。

sequenceDiagram
    participant App
    participant Client

    App->>App: Produce Item 1
    App->>Client: Send Item 1
    App->>App: Produce Item 2
    Client->>Client: Process Item 1
    App->>Client: Send Item 2
    App->>App: Produce Item 3
    Client->>Client: Process Item 2
    App->>Client: Send Item 3
    Client->>Client: Process Item 3
    Note over App: Keeps producing...
    Note over Client: Keeps consuming...

它甚至可以是無限串流,你可以一直持續傳送資料。

JSON Lines

在這些情況下,常見做法是傳送「JSON Lines」,這是一種每一行各包含一個 JSON 物件的格式。

回應的 content type 會是 application/jsonl(而不是 application/json),而本體內容會像這樣:

{"name": "Plumbus", "description": "A multi-purpose household device."}
{"name": "Portal Gun", "description": "A portal opening device."}
{"name": "Meeseeks Box", "description": "A box that summons a Meeseeks."}

它和 JSON 陣列(相當於 Python 的 list)很像,但不同於用 [] 包起來並以 , 分隔項目,它是每一行各放一個 JSON 物件,彼此以換行字元分隔。

/// info

重點在於你的應用能夠逐行產生資料,同時用戶端在消耗前一行的資料。

///

/// note | 技術細節

由於每個 JSON 物件會以換行分隔,它們的內容中不能包含實際的換行字元,但可以包含跳脫後的換行(\n),這是 JSON 標準的一部分。

不過通常你不需要為此煩惱,這些都會自動處理,繼續往下看吧。🤓

///

使用情境

你可以用這種方式從 AI LLM 服務、日誌遙測串流資料,或任何能以 JSON 項目結構化的其他型態資料。

/// tip

如果你想串流二進位資料,例如影像或音訊,請參考進階指南:串流資料

///

使用 FastAPI 串流 JSON Lines

要用 FastAPI 串流 JSON Lines,你可以在你的路徑操作函式中改用 yield 逐一產生項目,而不是用 return

{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}

如果你要回傳的每個 JSON 項目型別都是 Item(一個 Pydantic 模型),而且該函式是 async,你可以將回傳型別宣告為 AsyncIterable[Item]

{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}

如果你宣告了回傳型別,FastAPI 會用它來進行資料的驗證、在 OpenAPI 中文件化過濾,並使用 Pydantic 進行序列化

/// tip

由於 Pydantic 會在 Rust 端進行序列化,宣告回傳型別可獲得比未宣告時高得多的效能

///

非 async 的路徑操作函式

你也可以用一般的 def 函式(沒有 async),同樣用 yield

FastAPI 會確保正確執行,不會阻塞事件迴圈。

因為這種情況下函式不是 async,正確的回傳型別會是 Iterable[Item]

{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}

不宣告回傳型別

你也可以省略回傳型別。此時 FastAPI 會使用 jsonable_encoder 將資料轉換為可序列化為 JSON 的形式,然後以 JSON Lines 傳送。

{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}

伺服器推播事件(SSE)

FastAPI 也原生支援 Server-Sent Events(SSE),它們與此相當類似,但多了幾個細節。你可以在下一章學到更多:伺服器推播事件(SSE)🤓