PeerJS文件传输指南:ArrayBuffer与Blob大文件分块传输避坑清单
【免费下载链接】peerjsSimple peer-to-peer with WebRTC.项目地址: https://gitcode.com/gh_mirrors/pe/peerjs
PeerJS 是基于 WebRTC 的开源点对点库,一行send()就能在两台浏览器之间传输数据,但大文件传输恰恰是新手最容易踩坑的地方:ArrayBuffer 何时被分块?Blob 和 File 到达对端会变成什么类型?8MB 缓冲背压又是怎么回事?本文结合 PeerJS 源码与端到端测试用例,给出一份完整的PeerJS 文件传输避坑清单,帮你一次讲清 ArrayBuffer 与 Blob 的分块传输机制。
先看懂:PeerJS 文件传输的 3 层管线
在动手之前,先知道一条conn.send(bigFile)背后发生了什么。PeerJS 的数据连接由三层机制组成:
| 层级 | 职责 | 关键阈值 | 源码位置 |
|---|---|---|---|
| 序列化层 | 把 ArrayBuffer / Blob / JSON 等数据编码为二进制 | — | BinaryPack.ts |
| 分块层 | 超大的包自动切成小块逐片发送 | 16300 字节 | binaryPackChunker.ts |
| 背压层 | 发送队列积压时暂停发送,防止内存爆炸 | 8 MB | DataConnection.ts |
理解这 3 层,下面所有的坑都能迎刃而解。
快速上手:3 步发送一个文件
PeerJS 通过npm install peerjs安装,核心用法极简——建立数据连接、等open事件、调用send():
import { Peer } from "peerjs"; const peer = new Peer("my-id"); // 发送端:连接并发送 File peer.on("open", () => { const conn = peer.connect("another-peers-id"); conn.on("open", () => { const file = new File([arrayBuffer], "report.bin", { type: "application/octet-stream" }); conn.send(file); // 超大文件会自动分块,无需手动处理 }); }); // 接收端 peer.on("connection", (conn) => { conn.on("data", (data) => { console.log(data); // 注意:这里收到的是 ArrayBuffer,不是 Blob }); });更多基础用法可参考 README.md 与交互式演示页 serialization.html。
ArrayBuffer 分块传输原理:为什么是 16300 字节?
很多教程说"分块大小设为 60000 字节",但 PeerJS 源码里写的是16300,这不是笔误:
readonly chunkedMTU = 16300; // The original 60000 bytes setting does not work // when sending data from Firefox to Chrome...(见 binaryPackChunker.ts)
原始 60000 字节设置会导致 Firefox 向 Chrome 发送数据时在 16384 字节处被"截断",所以 PeerJS 选择了安全的 16300 字节作为分块 MTU。
分块协议也很简单,每片数据都携带元信息(BinaryPack.ts):
__peerData:分块组的唯一 IDn:当前分块的序号total:总分块数data:本片的二进制内容
接收端收齐所有分块后,通过 concatArrayBuffers 自动拼装回完整的 ArrayBuffer,再触发data事件。你无需自己写任何拼装代码——只要不手动干预,完整性由 PeerJS 保证。
Blob 与 File 的正确用法:接收端拿到的是 ArrayBuffer
这是最反直觉的一点:PeerJS 官方端到端测试中,发送Blob/File,对端收到的是 ArrayBuffer,而不是 Blob:
- blobs.js:
dataConnection.send(new Blob([json]))发送 Blob - files.js:
dataConnection.send(new File(...))发送文件 - 两者断言接收到的都是
ArrayBuffer(files.js)
也就是说,如果接收方想还原成文件下载链接,需要自己执行一步:
const blob = new Blob([data], { type: "application/octet-stream" }); const url = URL.createObjectURL(blob);避坑清单:7 个高频错误对照表
| # | 坑 | 现象 | 正确做法 |
|---|---|---|---|
| 1 | 在open事件前调用send() | 触发NotOpenYet错误,消息直接丢弃 | 先监听open再发送(见 DataConnection.ts) |
| 2 | 自己手动把大文件切成小片发送 | 与内置分块器叠加,接收端语义错乱 | 直接send()整个 ArrayBuffer / Blob,交给 BinaryPackChunker |
| 3 | 循环高频send()大对象 | 发送队列超过 8MB 后触发背压,数据被挂起、延迟飙升 | 控制发送节奏,利用conn.bufferSize观察积压(BufferedConnection.ts) |
| 4 | 跨浏览器传输时自行改 MTU 为 60000 | Firefox → Chrome 方向数据在 16384 字节处截断 | 保持默认的 16300 字节分块阈值 |
| 5 | 以为接收到的还是 Blob / File | instanceof Blob判断失败,后续处理报 undefined | 按 ArrayBuffer 接收,必要时自行new Blob([data]) |
| 6 | 直接close()想"发完再断" | 已缓冲未发的数据被清空丢弃 | 用close({ flush: true })先冲刷缓冲区再关闭(BufferedConnection.ts) |
| 7 | 大文件用 JSON 序列化传输 | 体积膨胀严重、性能差 | 默认使用 binary(BinaryPack)序列化,文本数据也可转 ArrayBuffer 发送 |
其中第 3 条值得展开:当dataChannel.bufferedAmount超过 8MB(MAX_BUFFERED_AMOUNT,见 DataConnection.ts)时,PeerJS 会暂停发送并等 50ms 后重试(BufferedConnection.ts)。这是保护机制而非故障——但如果你疯狂调用send(),页面会长时间卡在这个"憋气"状态。
验证你的传输:官方端到端测试矩阵
不确定自己传的数据类型是否被支持?PeerJS 内置了一整套数据通道序列化测试,覆盖了几乎所有常见场景:
- 二进制类:arraybuffers.js、Uint8Array.js、Int32Array.js、typed_array_view.js
- 文件类:blobs.js、files.js
- 大字符串:long_string.js(重复 10 万次的长字符串)
- 测试数据源:data.js、commit_data.js
- 测试流程编排:serializationTest.ts
对照这份矩阵自查:你传的数据类型在测试里能找到对应文件,就放心传。
总结
PeerJS 把文件传输最脏的活——序列化、分块、拼装、背压——都封装好了。新手要记住的只有三件事:
- 等
open再发送,别提前抢跑; - 别手动分块,16300 字节的自动分块器已经处理了跨浏览器兼容;
- 接收端按 ArrayBuffer 处理,Blob / File 不会以原类型到达对端。
照这份避坑清单走,PeerJS 的 WebRTC 点对点大文件传输会变得和console.log一样省心。
【免费下载链接】peerjsSimple peer-to-peer with WebRTC.项目地址: https://gitcode.com/gh_mirrors/pe/peerjs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考