我想使用JSON发送大字节数组(这个问题启发了我),为了减少开销,我想使用base128编码(实际上可以产生有效的json字符串)。但不幸的是,我无法找到一些在JS中进行转换的过程。我将发布过程作为对此问题的答案,但是可能是某个过程较短的人,或者是在JSON中有效发送二进制数据的更好的主意。
编码
\nlet bytesToBase128 = (bytesArr) => {\n // 128 characters to encode as json-string\n let c= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\xc2\xbc\xc2\xbd\xc3\x80\xc3\x81\xc3\x82\xc3\x83\xc3\x84\xc3\x85\xc3\x86\xc3\x87\xc3\x88\xc3\x89\xc3\x8a\xc3\x8b\xc3\x8c\xc3\x8d\xc3\x8e\xc3\x8f\xc3\x90\xc3\x91\xc3\x92\xc3\x93\xc3\x94\xc3\x95\xc3\x96\xc3\x97\xc3\x98\xc3\x99\xc3\x9a\xc3\x9b\xc3\x9c\xc3\x9d\xc3\x9e\xc3\x9f\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4\xc3\xa5\xc3\xa6\xc3\xa7\xc3\xa8\xc3\xa9\xc3\xaa\xc3\xab\xc3\xac\xc3\xad\xc3\xae\xc3\xaf\xc3\xb0\xc3\xb1\xc3\xb2\xc3\xb3\xc3\xb4\xc3\xb5\xc3\xb6\xc3\xb7\xc3\xb8\xc3\xb9\xc3\xba\xc3\xbb\xc3\xbc\xc3\xbd\xc3\xbe\xc3\xbf" \n let fbits=[]; \n let bits = (n,b=8) => [...Array(b)].map((x,i)=>n>>i&1); \n bytesArr.map(x=> fbits.push(...bits(x)));\n\n let fout=[]; \n for(let i =0; i<fbits.length/7; i++) { \n fout.push(parseInt(fbits.slice(i*7, i*7+7).reverse().join(\'\'),2)) \n }; \n\n return (fout.map(x => c[x])).join(\'\');\n}\n\n// Example\n// bytesToBase128([23, 45, 65, 129, 254, 42, 1, 255]) => "N\xc3\x9a4A\xc3\xa8\xc3\x9f\xc3\x8a0\xc3\xbf1"\nRun Code Online (Sandbox Code Playgroud)\n解码
\nlet base128ToBytes = (base128str) => {\n // 128 characters to encode as json-string\n let c= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\xc2\xbc\xc2\xbd\xc3\x80\xc3\x81\xc3\x82\xc3\x83\xc3\x84\xc3\x85\xc3\x86\xc3\x87\xc3\x88\xc3\x89\xc3\x8a\xc3\x8b\xc3\x8c\xc3\x8d\xc3\x8e\xc3\x8f\xc3\x90\xc3\x91\xc3\x92\xc3\x93\xc3\x94\xc3\x95\xc3\x96\xc3\x97\xc3\x98\xc3\x99\xc3\x9a\xc3\x9b\xc3\x9c\xc3\x9d\xc3\x9e\xc3\x9f\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4\xc3\xa5\xc3\xa6\xc3\xa7\xc3\xa8\xc3\xa9\xc3\xaa\xc3\xab\xc3\xac\xc3\xad\xc3\xae\xc3\xaf\xc3\xb0\xc3\xb1\xc3\xb2\xc3\xb3\xc3\xb4\xc3\xb5\xc3\xb6\xc3\xb7\xc3\xb8\xc3\xb9\xc3\xba\xc3\xbb\xc3\xbc\xc3\xbd\xc3\xbe\xc3\xbf" \n\n dfout = base128str.split(\'\').map(x=>c.indexOf(x));\n let dfbits = [];\n let bits = (n,b=8) => [...Array(b)].map((x,i)=>n>>i&1);\n dfout.map(x=> dfbits.push(...bits(x,7) ));\n\n let dfbytes=[]; \n let m1 = dfbits.length%8 ? 1 : 0;\n for(let i =0; i<dfbits.length/8-m1; i++) { \n dfbytes.push(parseInt(dfbits.slice(i*8, i*8+8).reverse().join(\'\'),2)) \n }; \n\n return dfbytes;\n}\n\n// Example\n// base128ToBytes("N\xc3\x9a4A\xc3\xa8\xc3\x9f\xc3\x8a0\xc3\xbf1") => [23, 45, 65, 129, 254, 42, 1, 255]\nRun Code Online (Sandbox Code Playgroud)\n我在这里嵌入了bits函数 - here。这里的转换思想是将字节数组转换为位数组,然后将每7位(值从0到127)作为字符列表中的字符号c。在解码时,我们将每个字符数更改为7位数字并创建数组,然后将该数组的每个8位包解释为字节。
要查看 ASCI 字符并从中选择 128(这是任意的),我在控制台中输入
\n[...Array(256)].map((x,i) => String.fromCharCode(i)).join(\'\');\nRun Code Online (Sandbox Code Playgroud)\n我尽量避免使用在不同上下文中具有“特殊含义”的字符,例如 ! @ # $ % \' & ...
这是工作示例(转换Float32Array为 json)。
在 Chrome、Firefox 和 Safari 上测试
\n将字节数组转换为 base128 字符串(这是有效的 json)后,输出字符串小于15%输入数组。
再深入一点,并揭示当我们发送代码大于 128 ( \xc2\xbc\xc2\xbd\xc3\x80\xc3\x81\xc3\x82\xc3\x83\xc3\x84...) 的字符时,chrome 实际上发送两个字符(字节)而不是一个:( - 我以这种方式进行测试:在 url 栏chrome 中输入: //net-internals/#events(并发送 POST 请求)并在URL_REQUEST> HTTP_STREAM_REQUEST > UPLOAD_DATA_STREAM_INIT >total_size中我们看到,当正文包含大于 128 的字符女巫代码时,请求会变大两倍。所以事实上我们没有发送这个字符会带来好处:(。对于base64字符串,我们没有观察到这种负面行为 - 但是我离开了这个程序,因为它们可能会用于发送以外的其他目的(例如比base64更好的替代方案在本地存储中存储二进制数据 - 但可能存在甚至更好的方法...?)。在这里更新 2019 年 。
| 归档时间: |
|
| 查看次数: |
536 次 |
| 最近记录: |