如何在浏览器中区分WebSocket文本与二进制消息?
当然可以!既然你能同时控制WebSocket的服务端和客户端,区分JSON文本消息和JPEG二进制消息其实有好几种省心的方案,我给你挑几个最实用的:
方案1:利用WebSocket原生的消息类型区分(最推荐)
WebSocket本身就支持发送文本类型和二进制类型两种消息,这刚好匹配你的JSON(文本)和JPEG(二进制)场景,完全不需要修改数据包内容,是最简洁的方案。
服务端(Node.js)代码示例:
// 发送JSON文本消息(默认就是文本类型) const jsonMessage = { status: "ok", data: "some info" }; ws.send(JSON.stringify(jsonMessage)); // 发送JPEG二进制消息(指定binary参数) const fs = require('fs'); const jpegBuffer = fs.readFileSync('./target.jpg'); ws.send(jpegBuffer, { binary: true });
客户端代码示例:
ws.onmessage = (event) => { // 判断消息类型:字符串就是JSON文本 if (typeof event.data === 'string') { try { const jsonData = JSON.parse(event.data); console.log('收到JSON消息:', jsonData); // 这里处理你的JSON逻辑 } catch (e) { console.error('不是合法JSON的文本消息:', event.data); } } // Blob/ArrayBuffer就是二进制JPEG else if (event.data instanceof Blob) { const imgUrl = URL.createObjectURL(event.data); const img = document.createElement('img'); img.src = imgUrl; document.body.appendChild(img); // 记得用完释放URL,避免内存泄漏 img.onload = () => URL.revokeObjectURL(imgUrl); } };
方案2:自定义元数据前缀(兼容特殊场景)
如果因为某些限制没法用原生消息类型区分,你可以给每个数据包加个标识前缀,明确告诉客户端消息类型:
- JSON消息前缀用
[JSON],比如发送[JSON]{"type":"log","content":"hello"} - JPEG消息前缀用
[JPEG],服务端把前缀Buffer和JPEG文件Buffer拼接后发送
服务端发送JPEG的示例:
const fs = require('fs'); const prefix = Buffer.from('[JPEG]'); const jpegBuffer = fs.readFileSync('./target.jpg'); const combinedBuffer = Buffer.concat([prefix, jpegBuffer]); ws.send(combinedBuffer, { binary: true });
客户端处理示例:
async function parseMessage(event) { if (typeof event.data === 'string') { if (event.data.startsWith('[JSON]')) { const jsonStr = event.data.slice(6); // 去掉前缀 const jsonData = JSON.parse(jsonStr); console.log('JSON消息:', jsonData); } else { console.log('普通文本消息:', event.data); } } else if (event.data instanceof Blob) { const buffer = await event.data.arrayBuffer(); const uint8 = new Uint8Array(buffer); // 把前缀转成字符串判断 const prefix = new TextDecoder().decode(uint8.slice(0, 6)); if (prefix === '[JPEG]') { // 截取前缀后的部分作为JPEG数据 const jpegBlob = new Blob([uint8.slice(6)]); const imgUrl = URL.createObjectURL(jpegBlob); // 后续显示图片逻辑... } } } ws.onmessage = parseMessage;
方案3:利用数据包本身的特征判断(兜底方案)
就是你提到的,JSON以{"开头、JPEG以FF D8 FF开头的特征,这个可以作为兜底方案,在没法用前两种方案时使用:
客户端判断示例:
async function isJpeg(blob) { const buffer = await blob.arrayBuffer(); const uint8 = new Uint8Array(buffer); // JPEG的文件头签名:FF D8 FF return uint8.length >= 3 && uint8[0] === 0xFF && uint8[1] === 0xD8 && uint8[2] === 0xFF; } ws.onmessage = async (event) => { if (typeof event.data === 'string') { if (event.data.startsWith('{')) { // 处理JSON const json = JSON.parse(event.data); console.log(json); } else { // 其他纯文本 console.log('文本消息:', event.data); } } else if (event.data instanceof Blob) { if (await isJpeg(event.data)) { // 显示JPEG const imgUrl = URL.createObjectURL(event.data); const img = document.createElement('img'); img.src = imgUrl; document.body.appendChild(img); } else { console.log('其他二进制数据'); } } };
总的来说,方案1是最优解,它完全贴合WebSocket协议的设计,逻辑简洁且不容易出错。如果有特殊场景限制,再考虑方案2或3。
内容的提问来源于stack exchange,提问作者fadedbee
相关产品推荐
相关产品推荐

