教學

使用WebRTC建構瀏覽器到瀏覽器的檔案傳輸:建構TransP2P的經驗總結

深入技術剖析TransP2P的實作原理——WebRTC資料通道、中斷續傳、OPFS與IndexedDB對比,以及瀏覽器儲存的特性。

使用WebRTC建構瀏覽器到瀏覽器的檔案傳輸:建構TransP2P的經驗總結

WebRTC點對點檔案傳輸架構圖,展示瀏覽器之間的直接連接

本文深入剖析TransP2P的底層工作原理——包括WebRTC內部機制、瀏覽器儲存特性等技術細節。如果你只是需要使用指南,請查看教學。

概要: 我建構了一個完全在瀏覽器中執行的P2P檔案傳輸工具。無需安裝、無需伺服器中轉、無需帳戶。以下是我在WebRTC資料通道、中斷續傳和瀏覽器儲存方面學到的經驗。


大多數檔案傳輸工具都遵循相同的模式:上傳到伺服器、取得連結、接收者從伺服器下載。你的檔案至少會在一段時間內儲存在別人的基礎設施上。

我想嘗試一種不同的方法:如果檔案根本不需要離開瀏覽器呢?

這個問題催生了TransP2P——一個基於WebRTC的瀏覽器端P2P檔案傳輸工具。在本文中,我將介紹技術決策、比預期更困難的部分,以及幾乎沒有人討論的兩種瀏覽器儲存方案。


基本架構

理論上流程很簡單:

  1. 兩台裝置都開啟網站(無需安裝、無需帳戶)。
  2. WebSocket信令伺服器幫助它們交換SDP提議/回應和ICE候選者。
  3. 建立直接的WebRTC資料通道。
  4. 檔案被分塊並透過資料通道發送。
  5. 接收端重新組裝分塊並儲存檔案。

信令伺服器從不接觸檔案資料。一旦連線建立,它只是幫助維護連線。


所有內容都分塊——即使不需要

早期做出的一個重要決定:所有檔案在傳輸過程中都會被分塊,無論是否啟用中斷續傳。

另一種方案——將檔案作為單個blob發送——看起來更簡單,但很快就會出現問題。大檔案會阻塞主執行緒,任何網路問題都意味著從頭開始。

使用分塊時,每個區塊通常是64 KB。發送端透過資料通道串流傳輸區塊;接收端在記憶體中緩衝它們,並在載入時寫入磁碟。這樣速度最快,因為傳輸過程中沒有中間磁碟I/O——瓶頸是資料通道吞吐量,而不是磁碟。


中斷續傳問題(以及為什麼有兩種解決方案)

中斷續傳是最有趣的部分——瀏覽器差異迫使我們實作兩種完全不同的方案。

目標

如果傳輸中斷(網路斷開、使用者關閉標籤頁),接收端應該能夠從中斷點繼續,而不是從零開始。

核心思想很簡單:追蹤已接收的區塊,並在重新連線時告訴發送端從第N區塊開始。

但在哪裡儲存這些區塊是難點,因為瀏覽器不提供原始磁碟存取權限。而且它們肯定不會提供相同的API。

方案1:OPFS + 檔案系統存取API(Chrome、Edge、Firefox)

現代基於Chromium的瀏覽器和較新版本的Firefox支援Origin私有檔案系統(OPFS)。OPFS允許你在沙箱化的來源私有目錄中寫入檔案,而且速度很快——當與Web Workers一起使用時,寫入操作在主執行緒外進行。

我的實作:

  • 檔案區塊透過Web Worker的可寫串流直接寫入OPFS。這完全繞過了瀏覽器的記憶體限制——你可以處理千兆位元組大小的檔案。
  • 檔案中繼資料(區塊數量、已接收區塊索引、檔案名稱、總大小)儲存在IndexedDB中,因為它體積小、結構化且可查詢。

重新連線時,接收端查詢IndexedDB以檢查該檔案的傳輸是否已完成。如果沒有,它透過信令通道將最後成功接收的區塊索引發送給發送端。發送端跳過前面的部分,從該區塊開始。

方案2:僅使用IndexedDB(Safari / iOS)

Safari不支援從Web Workers存取OPFS,並且iOS上完全不支援檔案系統存取API。這意味著你無法在主執行緒外串流寫入磁碟。

對於Safari使用者,替代方案是所有內容都使用IndexedDB——包括檔案區塊和中繼資料。

這可行,但有上限。IndexedDB在刷新到磁碟之前將資料儲存在記憶體中,因此非常大的檔案最終會達到Safari的記憶體限制。特別是在iOS上,限制非常嚴格——檔案大小實際上受到限制,體驗會在傳輸開始前顯示大小警告來優雅降級。

這不理想,但很誠實。工具會告訴你瀏覽器能做什麼和不能做什麼,而不是默默地失敗。


信令:保持最小化

信令伺服器的唯一任務是在同級之間中繼SDP和ICE候選者,直到WebRTC連線建立。我使用WebSocket來實作——它簡單、廣泛支援且延遲低。

伺服器不驗證使用者(無需帳戶)、不在活動工作階段之外儲存訊息、也不知道正在傳輸什麼。一旦資料通道開啟,信令伺服器就與傳輸無關了。

在生產環境中,你確實需要STUN/TURN伺服器,以便NAT後面的同級能夠連線。我結合使用公共STUN伺服器和自代管的TURN伺服器來處理UDP被封鎖的場景。


繞過瀏覽器記憶體限制

這是最讓我驚訝的部分:資料通道本身沒有記憶體問題——接收端的儲存策略才有。

如果你接收一個2 GB的檔案並嘗試在ArrayBuffer中重新組裝它,瀏覽器會崩潰。關鍵是將傳入的區塊直接串流傳輸到儲存(OPFS或IndexedDB),而不在記憶體中儲存整個檔案。

使用OPFS + Web Worker,這完美工作——主執行緒保持回應,檔案永遠不會作為單個記憶體物件存在。這就是TransP2P能夠在支援的瀏覽器上處理多GB檔案的原因。

Safari和iOS Safari無法做到這一點,這又回到了雙方案的問題。這很好地提醒我們,"在瀏覽器中工作"和"在所有瀏覽器中同等工作"是兩個不同的概念。


非同步模式:當P2P不可行時

當兩個同級同時線上時,P2P非常棒。但有時你想發送檔案給還不線上的人,或者連線不斷失敗。

為此,TransP2P有一個可選的伺服器快取模式。你將檔案上傳到伺服器(加密,使用從未傳送到伺服器的隨機生成金鑰),取得下載連結或程式碼,然後接收者稍後擷取它。檔案會自動過期——要麼在設定時間後,要麼在達到下載次數後。

這是一個付費功能,因為它消耗伺服器資源,但加密設計意味著伺服器永遠看不到檔案內容。加密金鑰在用戶端生成並嵌入在下載連結片段中(#後面的部分),因此它根本不會到達伺服器。


我希望早點知道的事情

ICE候選者收集需要時間。 不要假設連線卡住了——它通常只需要多幾秒鐘。向使用者顯示回饋。

行動瀏覽器不是桌面瀏覽器。 iOS Safari是所有現代瀏覽器中限制最嚴格的。儘早在上面測試,而不是在發佈後。

資料通道可靠性與速度之間存在權衡。 ordered: true保證順序但在封包遺失時可能停滯。對於檔案傳輸,我選擇了ordered: true和區塊級驗證和——實際上停滯很少見,而順序錯誤更糟糕。

人們不理解"P2P"。 最大的UX挑戰不是技術性的——而是解釋為什麼檔案可以在不上傳的情況下傳輸。如果你建構類似的東西,花時間在"工作原理"的文案上。


試用 / 查看程式碼

TransP2P免費使用(P2P模式完全免費;伺服器快取是付費的)。無需帳戶,無需安裝:

https://transp2p.com

網站上還有一些更深入的文章,介紹P2P檔案傳輸的實際工作原理和基於雲端的檔案傳輸的隱藏隱私風險——如果你對非技術方面感興趣,這些文章是為普通讀者寫的。

如果你用WebRTC資料通道建構過東西,我很想聽聽你做了哪些權衡——特別是關於大檔案處理的。2026年瀏覽器儲存領域仍然很混亂,更多的實地報告將幫助每個人。


本文最初由TransP2P的作者撰寫。如果你正在開發P2P工具或瀏覽器端檔案傳輸,請隨時聯繫。

體驗 TransP2P

iPhone 傳 Android、手機傳電腦 — 無需安裝 App

開始傳輸檔案 →