内容相同, md5竟然不一样!?

618 阅读1分钟

现象

我生成 md5 签名, 竟然跟后台同事生成的不一样? 明明都是同样的内容!!

image.png

但是, 当我换一个库(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 了

stackoverflow.com/questions/1…

看看下面的代码:

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, 每个问题都给了我想要的答案。 没你我得死在这里 ❤️