javascript - 为什么 V8(一个 javascript 模块)反序列化两个 2 个不同的十六进制字符串但带来 2 个相同的对象?
问题描述
我试图弄清楚为什么会发生这种情况。
const v8 = require('v8')
let stringa = 'ff0d6f220762616c616e63655a200070824fdc89df747141410000000000220a6465706c6f7965644279220673797374656d220773746f726167656f220a63616e646964617465736f222c49364e4d6f2b4b5a3531634b2b39626f6543554f716e6570724361723566727752746771746c493350596b3d6f2205626c6f636b4e000000000000244022076465706f7369745a20000088b116afe3b5020000000000000022046e616d65220d4e65772056616c696461746f7222086f70657261746f72222b74676c6331613979667337653765763270376a6164396b71757774767870637a6e6e65633432327564726b7b04222c576b5a6c346470454666797436585a506662433270766f5777424d6a314f497161794958304b47714a654d3d6f2205626c6f636b4e000000000000000022076465706f7369745a20000088b116afe3b5020000000000000022046e616d65221147656e657369732056616c696461746f7222086f70657261746f72222b74676c6331613979667337653765763270376a6164396b71757774767870637a6e6e65633432327564726b2206766f746572736f222b74676c6331613979667337653765763270376a6164396b71757774767870637a6e6e65633432327564726b5a200000e8c69583abe311000000000000007b017b057b02220877697468647261776f222b74676c6331613979667337653765763270376a6164396b71757774767870637a6e6e65633432327564726b6f49005a100000dcce86b42ad07b017b017b02220673797374656d547b04'
let a = v8.deserialize(Buffer.from(stringa, 'hex'))
console.dir(a, {depth: null})
let stringb = 'ff0d6f220762616c616e63655a200070824fdc89df747141410000000000220a6465706c6f7965644279220673797374656d220773746f726167656f220a63616e646964617465736f222c49364e4d6f2b4b5a3531634b2b39626f6543554f716e6570724361723566727752746771746c493350596b3d6f2205626c6f636b491422076465706f7369745a20000088b116afe3b5020000000000000022046e616d65220d4e65772056616c696461746f7222086f70657261746f72222b74676c6331613979667337653765763270376a6164396b71757774767870637a6e6e65633432327564726b7b04222c576b5a6c346470454666797436585a506662433270766f5777424d6a314f497161794958304b47714a654d3d6f2205626c6f636b490022076465706f7369745a20000088b116afe3b5020000000000000022046e616d65221147656e657369732056616c696461746f7222086f70657261746f72222b74676c6331613979667337653765763270376a6164396b71757774767870637a6e6e65633432327564726b2206766f746572736f222b74676c6331613979667337653765763270376a6164396b71757774767870637a6e6e65633432327564726b5a200000e8c69583abe311000000000000007b017b057b02220877697468647261776f222b74676c6331613979667337653765763270376a6164396b71757774767870637a6e6e65633432327564726b6f49005a100000dcce86b42ad07b017b017b02220673797374656d547b04'
let b = v8.deserialize(Buffer.from(stringb, 'hex'))
console.dir(b, {depth: null})
stringa
和之间明显不同stringb
。但是当我打印两个对象a
和b
. 我意识到他们是一样的。
谁能向我解释为什么?提前非常感谢大家。
解决方案
在SerializationTag定义的帮助下,手动解码这些字符串并不难,例如:
ff 0d // non-legacy version: 13
6f // object start
22 07 // one-byte string, length=7
62 61 6c 61 6e 63 65 // "balance"
5a 20 // bigint, bitfield: sign=0 length=16
00 70 82 4f dc 89 df 74 71 41 41 00 00 00 00 00
22 0a // one-byte string, length=10
64 65 70 6c 6f 79 65 64 42 79 // "deployedBy"
22 06 // one-byte string, length=6
73 79 73 74 65 6d // "system"
...
当你这样做的时间足够长时,你最终会看到它的stringa
用途:
22 05 // one-byte string, length=5
62 6c 6f 63 6b // "block"
4e // double
0000000000002440 // little-endian encoding of "10.0" as an IEEE754 double
而stringb
使用:
22 05 // one-byte string, length=5
62 6c 6f 63 6b // "block"
49 // int32
14 // "zig-zag" encoding of "10"
所以当你将这些字符串反序列化为 JavaScript 对象时,那么整数10
和双精度当然10.0
是无法区分的,因为在 JS 中,两者都是Number
s。
退后一步:不管这里的具体解释如何,依赖您无法控制的序列化格式的特定行为并不是一个好主意。它可能会发生不可预测的变化。V8 的序列化/反序列化 API 在底层所做的是一个内部实现细节(这也是没有关于它的文档的原因;你必须阅读源代码才能弄清楚),它可以改变。而且,事实上,它确实改变了!该字符串的序列化格式版本为 13,这意味着在此之前还有 12 个其他版本,并且可以随时推出新版本。
即使除了新的序列化格式版本之外,我还能想到几个其他原因,为什么不同的编码可以反序列化为外观相同的 JS 对象(例如字符串编码、NaN 模式、varint 或 BigInt 数据中的前导零、可选的可忽略字节......) .
如果您需要对对象的序列化格式做出任何保证,您应该实现自己的序列化算法,以便确保这些保证确实成立。
推荐阅读
- android - 更改 Android 日历事件的颜色
- apache-spark - 火花错误:java.lang.NoClassDefFoundError:org/apache/spark/sql/sources/v2/StreamWriteSupport
- gradle - 当依赖项不可用时,Gradle 构建失败
- sql - 带有可以返回空值的连接的 SQL 添加
- asp.net-core - 部署错误:“无法访问请求的页面,因为该页面的相关配置数据无效”
- powershell - 使用 powershell 从值中获取完整的注册表项路径
- xcode - 如何在swift中准备矩形类型的标签栏?
- xamarin.forms - 单击警报外部时如何限制显示警报的关闭
- android - 如何以编程方式更改代码中的 tabContentStart 值?
- javascript - 使用 jquery 计算多数据属性