如何将 Javascript 对象转换为节点缓冲区?
Posted
技术标签:
【中文标题】如何将 Javascript 对象转换为节点缓冲区?【英文标题】:How to convert a Javascript Object to a Node Buffer? 【发布时间】:2016-07-08 20:01:17 【问题描述】:我在我的节点服务器上使用Buffer
,在我的Javacript客户端上使用Buffer
。
为了节省字节,我希望通过 websockets 将我的数据作为二进制而不是 JSON 发送到服务器。
所以,如果我有 [ 5, false, 55, "asdf" ]
的 javascript 对象,我想在发送之前将其转换为客户端上的缓冲区。也许是这样的:
object.toBuffer('int16', 'bool', 'int16', 'utf8');
并在服务器上读取它,如下所示:
var obj = buffer.read('int16', 'bool', 'int16', 'utf8');
我正在查看当前的解决方案,看起来我可能只需要做很多concat
ing、指定字节偏移/长度、从整数转换为布尔值等。
有没有更好的办法?
编辑:以下是我认为您目前必须这样做的方式。我想我的问题只是它过于冗长且容易出错,我正在寻找一种更简洁优雅的方式来完成它,因为此操作将在我的代码中的许多不同位置执行。
// On client for [ 5, false, 55, "test" ]
const writeFirst = Buffer.allocUnsafe(2);
writeFirst.writeInt16LE(5, 0);
const writeSecond = Buffer.allocUnsafe(1);
writeSecond.writeUInt8(0);
const writeThird = Buffer.allocUnsafe(2);
writeThird.writeInt16LE(55, 0);
const writeFourth = Buffer.from('test');
const result = Buffer.concat([writeFirst, writeSecond, writeThird, writeFourth]);
// On server for reading buffer of [ 5, false, 55, "test" ]
const readFirst = result.readInt16LE(0);
const readSecond = Boolean(result.readUInt8(2));
const readThird = result.readInt16LE(3);
const readFourth = result.toString('utf8', 5);
编辑#2:正在谷歌搜索,我想我可能想要协议缓冲区之类的东西。我不确定它们是什么或者它们是否适用,但看起来你可以在文件中为所有消息指定一个模式,然后将你的 JSON 对象序列化到该模式并让它返回一个缓冲区,然后你可以在客户端/其他服务器上使用相同的模式进行反序列化。我将对此进行更多研究。
【问题讨论】:
无论如何,您都必须将 Buffer 转换为 Blob 才能在 Socket 上发送()它,而 gzip 应该负责 JSON 重复,而数组几乎没有。 @dandavis:为什么它必须是一个 blob?你不能connection.binaryType = "arraybuffer";
吗?
嗯,也许吧,我不知道这是一个 Socket 选项,上次我弄脏了,只有 Blob 在我的项目中工作......
你试过Buffer.from([5, false, 55, 'asdf'], 'binary');
吗?
@peteb:我认为这不适用于字符串。
【参考方案1】:
缓冲区的第一个参数必须是:String、Buffer、ArrayBuffer、Array 或类似数组的对象。
考虑到这些信息,我们可以通过从 String 创建缓冲区来实现您正在寻找的内容。它看起来像下面这样:
let json = [ 5, false, 55, 'asdf' ];
let buffer = Buffer.from(JSON.stringify(json));
console.log('Buffer: ', buffer); // Buffer: <Buffer 5b 20 35 2c 20 66 61 6c 73 65 2c 20 35 35 2c 20 22 61 73 64 66 22 20 5d>
然后你可以像这样带回你的 JSON:
let converted = JSON.parse(buffer);
console.log('Parsed to json', converted); // Parsed to json [ 5, false, 55, 'asdf' ]
【讨论】:
new Buffer()
目前已被弃用(即使它仍在节点 8.2 中工作)。支持的方法是Buffer.from(<string>)
嗨,如果我的 JSON 对象有 1)文件名(字符串)和 2)实际的二进制数据,如果我要 JSON.stringify 整个事情,ArrayBuffer(对我来说我正在使用browser javasript) 将在 stringify 中丢失。有没有办法直接把JSON转成arraybuffer,或者给arraybuffer加一个header?【参考方案2】:
当我们在 NodeJS 环境中时,我们有比Buffer.from(JSON.stringify(data))
更好的选择。
性能方面 JSON.stringify + Buffer.from() 是可以的,但如果对象包含 ArrayBuffer 则无法解决,如果完成,则效率非常低。
纯 NodeJS 环境的最佳方式
使用“v8 序列化 API”Node JS v8 docs
它易于使用并内置于 Node.js 二进制文件中。
它是同类序列化器中速度最快、空间效率最高的。
const serialize, deserialize = require("v8")
const photo =
name: "rabbit",
height: 1220,
width: 1440,
tinyThumbnail: jpegFileAsBuffer,
mediumThumbnail: anotherJpegFileAsBuffer,
description: "some string data",
metaData:
tags: ["rabbit", "animal", "runner"],
type: "image/jpeg"
const photoSerializedAsBuffer = serialize(photo)
const deserialisedBack = deserialize(photo)
但唯一的问题是,这只适用于 NodeJS。如果你想使用“v8”库,还有 C++(我个人不喜欢这样做)。
用于多平台支持
使用“bson”(MongoDB BSON)
在性能方面它接近 v8 解析器,但它可以适用于支持 MongoDB 的所有平台、NodeJS、Web 中的 JS、Java、C++、rust、ruby、python....
用法和v8序列化API一模一样
const serialize, deserialize = require("bson")
const photo =
name: "rabbit",
height: 1220,
width: 1440,
tinyThumbnail: jpegFileAsBuffer,
mediumThumbnail: anotherJpegFileAsBuffer,
description: "some string data",
metaData:
tags: ["rabbit", "animal", "runner"],
type: "image/jpeg"
const photoSerializedAsBuffer = serialize(photo)
const deserialisedBack = deserialize(photo)
但是当 BSON 类型启动时会变得很困难。但是如果知道对象结构,这应该不是问题,并且在处理跨平台的东西时不太可能不知道对象结构。
然而,在 NodeJS 中一个快速的解决方案是使用 bson-buffer
终于
这不是一个完整的证明解决方案,但适用于 NodeJS,并计划很快为 web JS 推出此解决方案。
tabular-json-node
由于其简单的表格结构,我们也可以支持其他平台。如果有人想在这方面进行合作,请随时联系。
【讨论】:
以上是关于如何将 Javascript 对象转换为节点缓冲区?的主要内容,如果未能解决你的问题,请参考以下文章
我有一个对象的 .log 文件,如何将它们转换为 JSON 对象以便在 Javascript 中进行迭代?