Boloop 製作的閱讀示意圖:保留檔案,先核對結果不明的上傳,再決定是否重試寫入。
上傳按鈕一直轉,最後報了逾時,第一反應通常是再點一次。但這個動作隱含了一個未經確認的判斷:剛才的檔案一定沒有上傳成功。
Boloop 在 2026 年 10 月 16 日遇到過一次結果不明的上傳操作。管理員身分已經在實際瀏覽器中確認,一份 Skill 草稿也已儲存;隨後,雲端瀏覽器的檔案選擇與上傳操作工具逾時,後續唯讀檢查沒有恢復可見狀態。
當時能確定的是工具沒有回傳可用結果。附件究竟有沒有寫入,仍然未知。我們沒有繼續盲目上傳,也沒有把這次逾時直接歸因於網站元件。
先確定逾時發生在哪一層
一次檔案上傳至少經過幾個邊界:操作工具選擇檔案,瀏覽器發出請求,伺服器接收並驗證,儲存完成寫入,用戶端讀取回應,再把附件關聯到資源。
其中任何一層停止等待,使用者都可能看到「逾時」。但上游停止等待,不表示下游一定停止工作。即使檔案已經到達儲存,回應沒有被瀏覽器讀到,介面也可能仍然不知道結果。
因此,排查時先記錄最後一個已知事實:檔案是否被選中、請求是否發出、是否收到回應、附件列表是否出現記錄、草稿是否已經關聯。缺哪一段,就把哪一段保留為未知。
那次 Boloop 事件中,支援的瀏覽器連線恢復方式未能恢復檢查,所以附件結果沒有得到確認。這個限制決定了下一步應等待可讀回狀態,而不是換一個說法宣布上傳失敗。
保留現場,比清空表單更有用
上傳遇到問題時,至少有兩份工作值得保留:已經填寫的內容,以及原來選擇的檔案。錯誤提示如果只剩下一句「失敗,請重新整理」,就把恢復成本都交給了使用者。
我們在檢查原始碼時,發現當時的上傳元件沒有 XHR 逾時設定,解析錯誤和同步初始化例外也可能讓介面停留在忙碌狀態。隨後準備的健壯性候選版本增加了 90 秒等待上限、較清楚的錯誤與不確定提示,以及檔案和草稿保留。
這個等待上限是候選實作的產品選擇,不能解釋為「上傳到 90 秒一定失敗」。逾時之後應該說停止等待,並引導使用者核對結果,不能保證伺服器沒有寫入。
候選版本還處理了元件卸載、舊回呼和初始化例外,防止一個已經失去脈絡的回應繼續改變目前介面。這些工作改善了可見的失敗恢復,但沒有因此查明瀏覽器操作工具為什麼逾時。
結果不明時,先做唯讀核對
恢復正常存取後,我會先看原草稿和附件庫。核對時使用檔案名稱、大小、資源歸屬和版本等實際資訊;如果存在同名檔案,進一步對照檔案位元組或檢查碼,不能只憑顯示名稱判斷。
接下來的動作取決於讀回結果:
| 讀回結果 | 適合的下一步 | |---|---| | 附件存在,草稿已正確關聯 | 繼續檢查內容,不再重複上傳 | | 附件存在,尚未關聯 | 核實它就是目標檔案,再完成關聯 | | 能確認附件未寫入 | 保留原檔案,按正常入口重試 | | 仍無法確認結果 | 保留未知狀態,先恢復觀察能力 |
這張表描述的是恢復方法,不是聲稱那次未知操作後來已經逐項完成。2026 年 10 月 16 日的記錄沒有確認上傳結果,也沒有確認該輪候選版本已經部署。
手動重試,也需要伺服器守住一致性
把重試按鈕留給使用者,不能替代伺服器約束。使用者可能連點,也可能在另一個分頁重複操作;網路重新連線以後,舊請求還可能回傳。
Boloop 早期的後端迴歸處理過同一資源與版本的重複綁定,要求以原子操作拒絕衝突,同時保留軟體不同平台、架構這類合法變體。附件仍被有效引用時,封存也要被阻止。
這些約束解決的是資料一致性。用戶端保留檔案和輸入,解決的是恢復體驗。兩者配合,才不會出現介面看似恢復,資料卻已經重複或引用錯亂的情況。
同樣,上傳成功也不等於內容已經公開。附件關聯、草稿儲存和明確發布仍是不同動作。恢復上傳時,不應順便替使用者執行發布。
怎麼驗證恢復,而不是只驗證報錯
早在另一輪隔離驗收中,我們注入過物件儲存故障。表單顯示安全錯誤,恢復儲存後,使用同一表單與原檔案手動重試,附件成功出現,未儲存內容也仍在。
這證明了那條受控故障路徑可以恢復。它沒有證明 10 月 16 日的操作工具逾時已被解決;一個發生在應用儲存層,一個發生在瀏覽器操作鏈上,證據不能互換。
對實際上傳問題,完整驗證還應繼續到正常管理員入口、上傳、儲存關聯、發布,以及公開下載後的位元組核對。只有走過這些步驟,才能對對應範圍作結論。
如果你正在實作一個上傳介面,可以先檢查三個小問題:等待是否有結束條件,失敗後原檔案與輸入是否還在,結果不明時能否查到權威記錄。它們比一個反覆出現的「重試」按鈕更能決定恢復是否順利。
而作為操作者,看到逾時時最值得停下來的地方,是下一次寫入之前。先查結果,再決定是否重試,往往能少製造一個新的問題。