教程

使用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模式完全免费;服务器缓存是付费的)。无需账户,无需安装:

/zh

网站上还有一些更深入的文章,介绍P2P文件传输的实际工作原理和基于云的文件传输的隐藏隐私风险——如果你对非技术方面感兴趣,这些文章是为普通读者写的。

如果你用WebRTC数据通道构建过东西,我很想听听你做了哪些权衡——特别是关于大文件处理的。2026年浏览器存储领域仍然很混乱,更多的实地报告将帮助每个人。


本文最初由快传TransP2P的作者撰写。如果你正在开发P2P工具或浏览器端文件传输,请随时联系。

体验 TransP2P

iPhone 传 Android、手机传电脑 — 无需安装 App

开始传输文件 →