WebSocket接收二进制数据时binaryType必须设为"blob",因默认以UTF-8解析导致非文本字节报错;该设置须在onopen前完成,否则无效;Blob可直接用URL.createObjectURL预览图片或标签下载,大文件需服务端分片、前端缓冲拼接。

WebSocket接收二进制数据时为什么binaryType必须设为"blob"
因为WebSocket默认以UTF-8字符串解析收到的数据,一旦遇到非文本字节(比如图片头部的0xFF 0xD8),就会触发onerror或解析失败。设binaryType = "blob"才能让onmessage事件的event.data是Blob对象而非乱码字符串。
注意:这个设置必须在WebSocket实例创建后、连接打开前完成,否则无效:
const ws = new WebSocket("wss://example.com");
ws.binaryType = "blob"; // ✅ 必须在这行放在 ws.onopen 之前
ws.onopen = () => { ... };
如果漏掉这行,event.data可能是ArrayBuffer(取决于浏览器默认值),也可能直接报错——不同浏览器行为不一致,不能依赖。
用URL.createObjectURL()快速预览Blob图片
接收到Blob后,最轻量的预览方式是生成临时URL并赋给<img>的src,不需要转成ArrayBuffer或base64:
立即学习“前端免费学习笔记(深入)”;
ws.onmessage = (event) => {
if (event.data instanceof Blob) {
const url = URL.createObjectURL(event.data);
document.getElementById("preview").src = url;
// 记得后续释放:URL.revokeObjectURL(url)
}
};
- 适用于JPEG/PNG/GIF等浏览器原生支持的图片格式
- 不消耗主线程CPU,比
FileReader.readAsDataURL()更高效 -
createObjectURL返回的URL只在当前文档生命周期有效,页面关闭自动清理;但若反复接收大量Blob,建议显式调用URL.revokeObjectURL()避免内存堆积
处理非图片文件(如PDF、ZIP)时怎么保存Blob
用户需要“下载”接收到的Blob文件,核心是构造<a>标签并触发点击,而不是用window.open()或location.href(后者对大文件易失败且无文件名):
ws.onmessage = async (event) => {
if (event.data instanceof Blob) {
const link = document.createElement("a");
link.href = URL.createObjectURL(event.data);
link.download = "received-file.bin"; // 可根据服务端元数据动态设名
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(link.href);
}
};
-
download属性在Firefox/Chrome/Safari中均有效,但仅对同源URL或Blob:协议URL生效(createObjectURL生成的正是后者) - 不要省略
document.body.appendChild()和removeChild(),否则某些浏览器(如旧版Safari)可能拒绝触发下载 - 服务端若能通过自定义HTTP头或消息体附带原始文件名(例如JSON封装:
{type: "file", name: "report.pdf", data: Blob}),就优先用它替换硬编码的download值
大文件传输时如何避免内存爆炸和卡顿
WebSocket一次性接收几MB甚至上百MB的Blob,会瞬间占满JS堆内存,导致页面假死。必须分片+流式处理:
- 服务端需按固定大小(如64KB)切分二进制数据,每片单独发一条
message,并附带序号和总片数(例如用Uint8Array前4字节存序号) - 前端用
ArrayBuffer手动拼接(不是Blob),因为Blob不可变,多次new Blob([blob1, blob2])会产生冗余拷贝 - 拼接完成后才调用
new Blob([buffer])生成最终Blob,再交给预览或下载逻辑 - 若需实时解码(如视频帧),考虑用
TransformStream+ReadableStream管道,但需检查目标浏览器是否支持(Chrome ≥ 109,Firefox ≥ 117)
关键点:Blob本身不提供流式读取能力,所有“边收边处理”的需求,都必须在服务端配合分片,前端配合缓冲与状态管理——单靠binaryType = "blob"解决不了大文件问题。



















