WebSocket本身不内置断点续传能力,必须靠前端状态管理、服务端分片确认与持久化上传进度三者协同实现;关键在于自定义通信协议层,每次发送分片需携带fileId、chunkIndex、offset等元信息,服务端记录已收分片,客户端重连后先查询进度再续传。

WebSocket本身不内置断点续传能力,必须靠前端状态管理 + 服务端分片确认 + 持久化上传进度三者协同才能实现。光建个WebSocket连接、send()一堆ArrayBuffer,断网重连后根本不知道该从哪片继续。
怎么让WebSocket知道“断在哪、续从哪”
关键不是WebSocket协议,而是你设计的通信协议层。每次发分片前,必须带上下文元信息;每次收响应后,必须持久化当前进度。
- 前端每次发送分片时,必须附带:
fileId(全局唯一标识)、chunkIndex、totalChunks、offset(字节偏移量)、md5(分片校验) - 服务端收到后,不能只存数据,必须写入临时存储(如Redis),记录
{fileId: {chunkIndex: true, uploadedSize: xxx}} - 客户端断线重连后,先发一个
GET_PROGRESS指令,服务端返回已成功接收的chunkIndex列表,前端据此跳过已传分片 - 本地进度不能只放内存——刷新就丢。必须用
localStorage或IndexedDB存fileId → {uploadedChunks: [0,1,3], offset: 15728640}
为什么不能直接 send(file.slice())
浏览器File.slice()返回的是Blob,而WebSocket.send()只接受String、ArrayBuffer、Blob(部分浏览器支持)、TypedArray。但直接传Blob有两大隐患:
- Chrome/Safari对
Blob通过WebSocket传输的支持不稳定,容易触发InvalidStateError或静默失败 -
Blob无法做流式校验,你没法在发送前计算md5,也无法控制是否压缩/加密 - 正确做法是用
FileReader.readAsArrayBuffer()读取后发送ArrayBuffer,再配合Uint8Array做内存视图操作 - 大文件别一次性读全:用
start/end参数分段读,避免主线程卡死和OOM
服务端收到二进制数据后怎么拼?
WebSocket服务端(如Java Session、Node.js ws库)接收到的是ByteBuffer或Buffer,但你不能简单追加写磁盘——分片可能乱序到达,也可能重复发送。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 必须按
fileId + chunkIndex为键,把每个分片存为独立临时文件(如/tmp/upload_abc123_part_5.bin),或存入对象存储的分片桶 - 服务端需维护一个
uploadStatus映射表,记录每个fileId的receivedChunks: Set<number></number>和totalSize - 只有当
receivedChunks.size === totalChunks时,才触发合并逻辑(如调用cat命令或fs.promises.appendFile) - 合并前必须校验每个分片的
md5,防止中间篡改或传输损坏 - 别等所有分片收完再存盘——内存扛不住。边收边落盘,校验失败立刻删对应临时分片
断网重连后如何避免重复上传同一片
这是最容易被忽略的环节:WebSocket自动重连后,前端如果没判断状态,会把已传成功的分片再发一遍,服务端若不做幂等处理,就会写坏文件。
- 前端每次发分片前,查本地
IndexedDB或localStorage,确认chunkIndex是否已在uploadedChunks里 - 服务端对每个
fileId + chunkIndex组合做幂等判断:若该分片已存在且md5一致,直接返回ALREADY_RECEIVED,不落盘 - 不要依赖
WebSocket连接ID做去重——重连后ID变了,但fileId必须由前端生成并全程携带 - 服务端超时清理策略要明确:比如30分钟内无新分片到达,自动删除该
fileId所有临时分片
真正难的从来不是“怎么发”,而是“怎么确认发到了、没发重、发错了能发现、断了知道从哪续”。WebSocket只是管道,断点续传的可靠性全压在协议设计和状态同步上。










