React 四條支線改 Flight 協定,回覆解碼免掃描
GitHub react/react releases · 2026-10-14
React 把 Server Components 的 Flight 傳輸協定改了:Server Function 回覆(reply)裡的串流欄位換了新的命名空間,伺服器端也不再用線性掃描去查 FormData。這份修改在 2026-10-14 同日發到四條支線:19.3.1、19.2.9、19.1.10、19.0.9,對應 PR #37845、#37844、#37843、#37842。
四個 release 的說明都只有一行:「Improve transport protocol」,沒有 CVE 字樣。內容要看 #37845:PR 描述為空,diff 動到 31 個檔案、+1525/-226 行,以下來自這份 diff。
原本的問題
客戶端用 processReply 把 Server Function 的參數打包成 FormData,伺服器端的 ReactFlightReplyServer 再逐欄位解回來。舊的 backing store 把整個 FormData 當資料庫用,用 get、getAll、delete 查欄位。新版原始碼註解直接寫明:這些操作在各大 runtime 都與欄位數成線性關係,解碼整體可能變成平方級。
另一個麻煩是「引用的 FormData」($K):舊程式每遇到一個引用,就從游標往後掃 key,靠前綴判斷歸屬。串流欄位與一般欄位共用同一種 key,只能邊掃邊讀值分辨。
核心改動
欄位依命名空間在寫入時就分類,查找時不再掃描。客戶端把串流(ReadableStream、async iterable)的欄位改寫成 prefix + 'S' + id:
// 舊:串流與一般 chunk 共用同一種 key
data.append(formFieldPrefix + streamId, partJSON);
// 新:串流走專屬命名空間
const streamPrefix = formFieldPrefix + 'S' + streamId;
data.append(streamPrefix, partJSON);伺服器端的 BackingFormData 依 key 在 appendBackingEntry 時分流:
prefix + '_':引用的 FormData,放進 append-only 陣列加游標。prefix + 'S':串流 chunk,同一個 key 累積成陣列,唯一允許重複的欄位。- 其他:一次性 chunk 進
Map,Blob 進另一個Map,按欄位名精確查找。
$K 的處理收斂成單一呼叫 consumeBackingEntries(formData, formPrefix),舊的掃描迴圈整段刪除。
其他同捆改動
同一個 PR 還改了兩處,release notes 都沒提。第一,ReactFlightClient 的 loadServerReference 現在只在 bound 參數是 React 自己的 ReactPromise 時才等待它,並在 key 為 then 或 id 不是字串時直接回傳 null。程式註解的理由是:其他東西可能是外來 thenable,不該呼叫它的 then。
第二,Node、Edge、Browser 三個 stream config 對空 buffer 與 detached ArrayBuffer 加了檢查。偵測到 detached buffer 會丟出 Cannot transport a detached buffer;在不支援 ArrayBuffer.prototype.detached 的環境,DEV 會警告「could be a security issue」並建議升級 Node.js。大於 VIEW_SIZE(4096)的 typed array 若不是橫跨整個 buffer,會先 slice() 複製再傳。
影響範圍
直接受影響的是跑 Server Functions 的部署:用 react-server-dom-webpack、react-server-dom-turbopack、react-server-dom-parcel 或 react-server-dom-esm 的框架與自建 RSC 伺服器。PR 的 package.json 變更涵蓋這些套件。純客戶端 React、不用 Server Components 的專案不會碰到這條路徑。
- 跑
19.0.x、19.1.x、19.2.x的人,升到各自支線的最新 patch,不必跨 minor。 - 大量欄位或大量串流參數的 Server Function 是這次解碼成本變化最明顯的場景;具體加速幅度,PR 與 release notes 都未公布。
- 欄位命名改變了。release notes 未說明新舊版本混用是否相容,客戶端 bundle 與伺服器端套件建議同批升級(此為依 diff 的推論,非官方說法)。