总之,在Node.js出现之前,JavaScript还是运行在浏览器端。处理Unicode编码的字符串数据很容易,但处理二进制和非Unicode编码的数据就无能为力了。但是需要在服务器端处理TCP和文件I/O。在Node.js中,提供了Buffer类来处理二进制数据,可以处理各种类型的数据。而在Node.js中,net、http、fs等一些重要的模块在数据传输和处理中都有Buffer,因为一些基础核心模块依赖于Buffer,所以在node启动的时候,Buffer就已经加载好了。我们可以直接在全局下使用Buffer。创建一个Buffer对象:newBuffer不安全?v6.0之前创建Buffer对象,直接使用newBuffer()构造函数创建对象实例,但是Buffer对内存的权限操作比较大,可以直接抓取一些敏感信息,所以v6.0之后,在官方文档推荐使用Buffer.from()接口创建Buffer对象。直接对比buffer.js的源码,看看两者的区别//Buffer构造函数Buffer(arg,encodingOrOffset,length)源码encodingOrOffset==='string'){thrownewError('如果指定了编码那么第一个参数必须是一个字符串');}返回Buffer.allocUnsafe(arg);}returnBuffer.from(arg,encodingOrOffset,length);}//Buffer.from函数源码Buffer.from=function(value,encodingOrOffset,length){if(typeofvalue==='number')thrownewTypeError('“值”参数不能是数字');if(isArrayBuffer(value)||isSharedArrayBuffer(value))returnfromArrayBuffer(value,encodingOrOffset,length);if(typeofvalue==='string')returnfromString(value,encodingOrOffset);从对象返回(值);};可以看到Buffer构造函数会判断第一个参数是否为数字类型,调用allocUnsafe接口或者直接调用from接口创建实例。两种创建方式唯一的区别在于,Buffer构造函数的第一个参数是第一个参数是数字类型,也就是说,如果我们使用构造函数方法创建,第一个参数不传递数字类型,和来自界面创建的逻辑一致,相对安全接下来我们看看为什么第一个传递的参数是数字,会存在安全隐患。如果第一个参数是数字,Buffer构造函数会为实例化的buffer分配一块内存空间,调用allocUnsafe接口对内存进行分类时,分配的内容空间没有初始化(数据没有重置),很可能携带缓存区前的数据。如果缓存中的内容是私钥、密码等敏感信息,则有可能被泄露,这里举例:varpassword='thisIsMyPassword';for(vari=0,i<100000;i++){varbuf=(newBuffer(200)).toString('ascii');if(buf.indexOf(token)!==-1){console.log('在i找到'+i+':'+buf);}}//密码内存申请的存储可能会在newBuffer中泄露出去,newBuffer()API的初始设计会让内存的分配非常快,因为不需要初始化和重置分配的内容空间每次。虽然具有一定的性能优势,但也存在一定的安全隐患。下面是具体的性能和耗时比较:console.time('new');for(vari=0;i<1000000;i++){newBuffer(2000);}console.timeEnd('new');console.time('alloc');for(vari=0;i<1000000;i++){Buffer.alloc(2000);}console.timeEnd('alloc');//运行结果,未初始化为fasterthaninitialized//new:1498ms//alloc:2439msv6.0之后的版本推荐使用Buffer.alloc()接口分配内存,使用Buffer.from()接口创建Buffer实例。同时,新版本还维护了Buffer.allocUnsafe()接口,但语义上面已经说的很清楚了。另外,在启用安全性方面,我们的业务--zero-fill-buffers默认启用了内存初始化。最后总结如下:使用newBuffer()构造创建Buffer对象实例的函数并非绝对不安全。alloc接口分配内存空间并初始化内存,不会泄漏旧缓存。必须有一个二进制的数据载体,ArrayBuffer对象、TypedArray对象、DataView对象都已经用JavaScript实现了,在ES6中被包含在ECMAScript规范中。事实上,这些数据结构在浏览器中也有使用,例如FileAPI、WebGL、Canvas、WebSockets等一些API的底层是二进制数据通信。查看node_buffer.cc的源码。Buffer在C++层面分配内存,最终以ArrayBuffer对象为载体。下面我们来区分一下ArrayBuffer、TypedArray和DataView的区别。ArrayBuffer对象:内存中的一段原始二进制数据,可以通过“查看”对其进行操作。TypedArray对象:用于生成内存视图。通过9个构造函数,可以生成9种数据格式视图。例如,Buffer中使用了Uint8Array(无符号8位整数)数组视图。DataView对象:暂时与本文无关,不再详细介绍。简单来说,Buffer模块使用v8::ArrayBuffer分配一块内存,通过v8::Uint8Array向TypedArray写入数据。说到Buffer内存分配,就不得不说到Buffer的8KB问题,对应buffer.js源码中的处理是Buffer.poolSize=8*1024;functionallocate(size){if(size<=0)返回新的FastBuffer();if(size
