Node.js Buffer

在ECMAScript 2015(ES6)引入TypedArray之前,JavaScript语言本身没有读取或者操纵二进制数据流的机制。Buffer类作为Node.js API的一部分引入,使得能够与TCP流或者文件系统操作等字节流交互。

既然ES6中已经加入了TypedArray,Buffer类以更优化与适用Node.js适用场合的方式实现Unit8Array API。Buffer类的实例类似于整型数组,但是对应于V8堆外固定大小原始内存分配。当Buffer创建时,确定其大小,并不能重新改变大小。

在Node.js内部,Buffer类是一个全局量,因此,不太可能需要这样使用

require('buffer').Buffer

例子:

// 创建长度为10的自动填充零值Buffer
const buf1 = Buffer.alloc(10);

// 创建长度为10的Buffer,填充值1
const buf2 = Buffer.alloc(10, 1);

// 创建长度为10的未初始化buffer
// 比调用Buffer.alloc()速度更快,但是返回Buffer实例可能会包含旧数据,
// 需要通过fill()或者write()方法重写
const buf3 = Buffer.allocUnsafe(10);

// 创建包含[0x1, 0x2, 0x3] buffer
const buf4 = Buffer.from([1, 2, 3]);

// 创建包含UTF-8字节 [0x74, 0xc3, 0xa9, 0x73, 0x74] buffer
const buf5 = Buffer.from('tést');

// 创建包含Latin-1字节[0x74, 0xe9, 0x73, 0x74] buffer
const buf6 = Buffer.from('tést', 'latin1');


Buffer.from()、Buffer.alloc()与 Buffer.allocUnsafe()

Node.js v6版本之前,通过Buffer构造函数创建相应实例,根据所提供的参数,分配返回不同buffer

  • 给Buffer()传入一个数值作为第一个参数,(例如:new Buffer(10)),分配一个新的特定大小Buffer对象。在Node.js 8.0.0之前,为这样的Buffer实例所分配的内存并未初始化,可以包含敏感数据。这样的Buffer实例必须随后进行初始化,通过或者 buf.fill(0) 或者通过完全写入Buffer。虽然这种行为意在改进性能,研发经历已经说明,在创建快速但未初始化的buffer与稍慢但是更安全的buffer之间需要更直接的区别。
    从Node.js 8.0.0开始,Buffer(num)与new Buffer(num)会返回初始化内存的Buffer
  • 传入字符串、数组或者Buffer作为第一个参数,拷贝对象数据到Buffer中
  • 传入ArrayBuffer返回与给定ArrayBuffer共享分配内存的Buffer

根据传入第一个参数值类型,new Buffer()行为方式变化非常大,如果应用程序没能合理校验传给new Buffer()的入参,或者未能合理初始化新分配的Buffer内容,可能会无意识的引入代码安全与稳定性问题。

为使得Buffer实例创建更可靠与少出差错,不同形式的new Buffer()构造函数已经被弃用,可以由其他单独方法Buffer.from()、Buffer.alloc()、Buffer.allocUnsafe()替代。

开发者应该将所有现存new Buffer()构造函数迁移到这些新API之一。

Buffer.from(array)  返回包含所提供字节副本的新Buffer

Buffer.from(arrayBuffer[, byteOffset [, length]])    返回新Buffer,与给定ArrayBuffer共享分配内存

Buffer.from(buffer)     返回新Buffer,包含给定Buffer内容副本

Buffer.from(string[, encoding])      返回新Buffer,包含所提供字符串副本

Buffer.alloc(size[, fill[, encoding]])   返回特定大小已填充Buffer实例,该方法会比 Buffer.allocUnsafe(size)慢得多,但是确保新创建Buffer实例不包含旧的前在敏感数据。

Buffer.allocUnsafe(size) 与Buffer.allocUnsafeSlow(size)    每一个返回特定大小新Buffer,内容必须用或者buf.fill(0)或者完全重写进行初始化。

由 Buffer.allocUnsafe()返回的Buffer实例可能会分配共享内部内存池,如果大小不超过Buffer.poolSize一半,由Buffer.allocUnsafeSlow()返回的实例从不使用共享内部内存池。

Buffer.allocUnsafe()与Buffer.allocUnsafeSlow()不安全原因分析

当调用方法Buffer.allocUnsafe() 和Buffer.allocUnsafeSlow()时,分配内存段并未初始化(并未清理处理)。虽然这种设计使得内存分配极其迅速,但是分配所得内存段可能会包含潜在敏感的旧数据。使用由Buffer.allocUnsafe() 方法创建的Buffer,但是未完全重写内存,在读Buffer内存时会泄露旧数据。

虽然使用Buffer.allocUnsafe() 方法会有明显的性能优势,必须额外小心避免引入应用程序安全隐患。

缓冲区与字符编码

Buffer实例常常用于表示已编码字符序列,例如UTF-8,UCS2,Base64或者甚至是16进制数据。通过使用明确字符编码方式可以在Buffer实例与普通JavaScript字符串之间相互转换。

例子:
const buf = Buffer.from('hello world', 'ascii');
// 打印输出: 68656c6c6f20776f726c64
console.log(buf.toString('hex'));

// 打印输出: aGVsbG8gd29ybGQ=
console.log(buf.toString('base64'));

当前NodeJS支持的字符编码方式包括:
'ascii' 只适合于7位ASCII数据,这种编码速度快,如果设定高位会去掉高位
'utf8' 多字节编码Unicode字符,很多网页与文档格式使用UTF-8
'utf16le' 2或4字节小端序编码Unicode字符,支持代理对 (U+10000至U+10FFFF)
'ucs2' 'utf16le'别名
‘base64’ Base64编码,当由字符串创建Buffer,该编码方式会正确接受“URL与文件名安全字母”,如RFC4648第五部分中指明的那样。
'latin1' 一种将Buffer编码为一字节已编码字符串的方式(IANA 在RFC1345第63页定义,Latin-1补充块与C0/C1控制码)
'binary' ‘latin1’别名
‘hex' 经每个字节编码为两个十六进制字符

注意事项:
现今浏览器遵循WHATWG说明,将'latin1'与ISO-8859-1均取别名为win-1252。这意味着在做像http.get()这样的事情,如果返回字符集是WHATWG说明中列出的字符集之中,很可能服务器端实际返回的是win-1252编码数据,使用'latin1'解码可能会错误解码。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值