现象
我生成 md5 签名, 竟然跟后台同事生成的不一样? 明明都是同样的内容!!
但是, 当我换一个库(js-md5), 却又生成了跟后台一致的值。
下面看看咋回事儿
代码
经过一系列排查,最终发现问题在于对中文的处理。
const forge = require('node-forge');
const jsmd5 = require('js-md5');
function md5(text) {
return forge.md.md5.create().update(text).digest().toHex();
}
const body = '啊';
contrast(body);
function contrast(text) {
const forgeRes = md5(text);
const jsmd5Res = jsmd5(text); // 生成了与后台一致的结果
console.log(
`----------------\ntext: ${text}\nforge: ${forgeRes}\njsmd5: ${jsmd5Res}`
);
}
输出👇:
----------------
text: "啊"
forge: 711716bf1fc529544aa68076ca766e5d
jsmd5: 04c16ff7b157d4b4702bb24aa62651a5
原因
一通查,竟然是因为字符集的问题, 提供给 forge 的字符串标记一下 utf8 , 结果就一致了。 代码如下:
function md5Utf8(text) {
return forge.md.md5.create().update(text, 'utf8').digest().toHex();
}
const forgeUtf8Res = md5Utf8(text); // 04c16ff7b157d4b4702bb24aa62651a5
//
但我的电脑的字符集就是 utf8 呀
但是!!! 我电脑默认的字符集不就是utf8, 怎么还要再转一下❓
铁证如山👇
echo $LANG # zh_CN.UTF-8
原来, Javascript 的字符串默认编码是 utf16 ! 这就解释了为什么我电脑的编码是 utf8 , 但是最终这个 "啊" 是 utf16 了
看看下面的代码:
const forge = require('node-forge');
const a = '啊'
const b = forge.util.encodeUtf8('啊')
const hexa = forge.util.createBuffer(a).toHex()
console.log('hexa', hexa);
const hexb = forge.util.createBuffer(b).toHex()
console.log('hexb', hexb);
console.log(`a: ${a}\nb: ${b}`)
// 输出
// hexa 554a
// hexb e5958a
// a: 啊
// b: å
一般 utf16 在表示汉字的时候, 通常会使用两个字节 (hexa 那样)。 utf8 通常是 3-4 个(hexb那样) , 破案了
最后
但是, 为什么b打印出来的不是 "啊" 呢?
直接上代码吧, 今日上班时间余量告急
// 代码来自chatgpt, 但我也跑过,可用。
const hexString = 'e5958a'; // 输入的十六进制字符串
// 将十六进制字符串转换为字节序列
const bytes = [];
for (let i = 0; i < hexString.length; i += 2) {
bytes.push(parseInt(hexString.substr(i, 2), 16));
}
// bytes -> [229, 149, 138]
// 使用 TextDecoder 对象解码为字符串
const decoder = new TextDecoder('utf-8');
const str = decoder.decode(new Uint8Array(bytes));
console.log(str); // 啊
感谢chatgpt, 每个问题都给了我想要的答案。 没你我得死在这里 ❤️