Tlv编码在NodeJs中的应用

2017年11月17日 · 254 字 · 2 分钟

最近在接入腾讯云的天御业务安全系统时接触到了TLV编码协议,好在TLV协议理解起来比较简单。故简要介绍一下该编码。

TLV编码是什么?

TLV是一种编码格式,编码如下:
[1-4字节] TYPE
[5-8字节] Value的Length
[9字节+] Value数据

本文只探讨无嵌套数据的情况。NodeJs操作二进制数据主要依赖于Buffer

编码

  1. 编码Ascii数据,由于ascii编码的数据,一个字节就是一个字符,所以比较简单
TYPE: 1
Value: test
  1. 根据编码规则,可以得出以下数据组装格式
[1-4字节] 00 00 00 01
[5-8字节] 00 00 00 04
[9-12字节] 74 65 73 74 
// 74 对应字符*t*ascii编码*116*的16进制形式,其他以此类推
  1. javascript代码
// buf总长度为4字节TYPE+4字节VALUE长度+test的字节数为12
const buf = Buffer.alloc(12);
// 写入TYPE
buf.writeIntBE(1, 0, 4);
// 写入LENGTH
buf.writeIntBE('test'.length, 4, 4);
// 写入test
buf.write('test', 8, 'test'.length);
// 此时buf就是编码结果,由于是二进制的,如果走TCP协议的话已经可以了,但是腾讯云要求base64编码。所以最终结果为
buf.toString('base64');
  1. 使用NodeJs交互式环境测试
➜  ~ node
> const buf = Buffer.alloc(12);
undefined
> buf
<Buffer 00 00 00 00 00 00 00 00 00 00 00 00>
> buf.writeIntBE(1,0,4)
4
> buf.writeIntBE(4,4,4)
8
> buf.write('test',8,4)
4
> buf
<Buffer 00 00 00 01 00 00 00 04 74 65 73 74>
> buf.toString()
'\u0000\u0000\u0000\u0001\u0000\u0000\u0000\u0004test'
> buf.toString('base64')
'AAAAAQAAAAR0ZXN0'
> 

非Ascii编码问题

如果发送的数据是Ascii编码表之外的数据,就会用到多字节编码,此时以上方法会有问题。 得意与Buffer完善的API,Buffer.from方法可以接收一个字符串和一个编码得到一个Buffer数组。

上例可以改为使用Buffer.from的版本:

const valueBuf = Buffer.from(value, 'utf8');
const buf = Buffer.alloc(8 + valueBuf.length);
buf.writeIntBE(type, 0, 4);
buf.writeIntBE(valueBuf.length, 4, 4);
buf.write(value, 8, valueBuf.length);
buf.toString('base64');

由于value使用的utf8编码,所以utf8编码表中的数据该方法都可以成功编码,经过腾讯云接口调用测试也是OK的。

解码

说到编码就会有解码。解码是编码的逆运算,根据一样的规则还原数据而已。

  1. javascript代码
    // 假设str为base64编码之后Tlv数据
    const buf = new Buffer(str, 'base64'); // 还原为Buffer
    // 读取TYPE
    const type = buf.readIntBE(0, 4)
    // 读取VALUE长度
    const length = buf.readIntBE(4, 4)
    // 读取VALUE
    const valueBuf = Buffer.alloc(length);
    // 写入VALUE
    buf.copy(valueBuf, 0, 8, 8 + length);
    // 得到原始数据
    valueBuf.toString('utf8');
  1. 使用NodeJs交互式环境测试
➜  ~ node
> const str = 'AAAAAQAAAAR0ZXN0';
undefined
> const buf = new Buffer(str, 'base64');
undefined
> const type = buf.readIntBE(0,4);
undefined
> const length = buf.readIntBE(4,4);
undefined
> const value = Buffer.alloc(length);
undefined
> valueOf
[Function: valueOf]
> value
<Buffer 00 00 00 00>
> buf.co
buf.constructor  

buf.copyWithin   

buf.compare      buf.copy         

> buf.copy(value,0,8,8+length);
4
> value.to
value.toLocaleString  value.toString        

value.toJSON          

> value.toString()
'test'
> 

腾讯云天御业务安全系统

socket.io中如果需要接入该系统进行垃圾发言的过滤时,可以使用我开发的SDK tencent-cloud-defend