Javascript 为什么Node.js中的散列会以相同的字符给出不同的结果?

Javascript 为什么Node.js中的散列会以相同的字符给出不同的结果?,javascript,node.js,Javascript,Node.js,因此,我尝试使用此函数对节点js中的字符进行散列 crypto.createHash('md5')。update('emdash','ascii')。digest('hex') 给出md5散列 f37c6f3896b2c85fbbd01ae32e47b43f 并使用缓冲区 crypto.createHash('md5').update(新缓冲区('amble','ascii').toString()).digest('hex') 给出如下结果: 9b759040321a408a5c7768b45

因此,我尝试使用此函数对节点js中的字符进行散列
crypto.createHash('md5')。update('emdash','ascii')。digest('hex')
给出md5散列

f37c6f3896b2c85fbbd01ae32e47b43f

并使用
缓冲区

crypto.createHash('md5').update(新缓冲区('amble','ascii').toString()).digest('hex')

给出如下结果:

9b759040321a408a5c7768b4511287a6

我试着调试
Hash.update()
,看看里面有什么,但我做不到,因为它看起来很难编译


为什么
加密
编码方法与
缓冲区
不同?什么使它与众不同?

加密编码方式与缓冲区编码方式相同,所以我们暂时忽略它。以下是问题的简化:

const text = '¤';
const b1 = Buffer.from(text, 'ascii');
const b2 = Buffer.from(b1.toString());
b1和b2不是相同的字节。b1是[0xa4],这并没有多大意义,因为0xa4不是ASCII的一部分。我不知道这是出于兼容性或性能原因还是什么原因,但这似乎是个坏主意,它会导致
Buffer.from(s,'ascii')
的值不同于
Buffer.from(Buffer.from(s,'ascii')。toString('ascii'),'ascii')
,并且似乎在任何地方都没有文档记录

在Node的现代版本中,默认编码是UTF-8,因此
b1.toString()
将尝试将
0xa4
解释为UTF-8,失败并生成替换字符(�) 相反,编码为[0xef,0xbf,0xbd]。在节点的非现代版本中,它将执行与环境相关的错误操作,而不是一致的错误操作

通过传递缓冲区而不是对缓冲区进行UTF-8编码,可以使您的操作得到相同的结果:

crypto.createHash('md5').update(new Buffer('¤', 'ascii')).digest('hex')
(注意如何删除
.toString()

但是,能够散列任何Unicode码点序列的正确代码将使用UTF-8

crypto.createHash('md5').update('¤', 'utf8').digest('hex')
crypto.createHash('md5').update(Buffer.from('¤', 'utf8')).digest('hex')

crypto的编码方式与缓冲区的编码方式相同,因此我们暂时忽略它。以下是问题的简化:

const text = '¤';
const b1 = Buffer.from(text, 'ascii');
const b2 = Buffer.from(b1.toString());
b1和b2不是相同的字节。b1是[0xa4],这没有多大意义,因为0xa4不是ASCII的一部分。我不知道这是出于兼容性或性能原因还是什么原因,但这似乎是个坏主意,它会导致
Buffer.from(s,'ASCII')
Buffer.from(Buffer.from)不同的值(s,'ascii')。toString('ascii'),'ascii')
,并且似乎没有在任何地方记录

在Node的现代版本中,默认编码是UTF-8,因此
b1.toString()
将尝试将
0xa4
解释为UTF-8,失败并生成替换字符(�) 相反,编码为[0xef,0xbf,0xbd]。在节点的非现代版本中,它将执行与环境相关的错误操作,而不是一致的错误操作

通过传递缓冲区而不是对缓冲区进行UTF-8编码,可以使您的操作得到相同的结果:

crypto.createHash('md5').update(new Buffer('¤', 'ascii')).digest('hex')
(注意如何删除
.toString()

但是,能够散列任何Unicode码点序列的正确代码将使用UTF-8

crypto.createHash('md5').update('¤', 'utf8').digest('hex')
crypto.createHash('md5').update(Buffer.from('¤', 'utf8')).digest('hex')

即使
new Buffer('.'','ascii').toString()=='.'.'
,您也缺少
update
的第二个参数。或者如果您打算传递原始二进制数据,而不让
update
处理编码,那么您可能不应该调用
.toString()
但却传递了缓冲区。@Bergi感谢您的回复,我刚刚意识到,utf-8中该字符的缓冲区是[194164],而ascii中该字符的缓冲区是[164],即使
新缓冲区(“·ascii”)。toString()=='·如果您缺少
更新
的第二个参数,或者如果您打算传递原始二进制数据而不让
更新
处理编码,那么您可能不应该调用
.toString()
但却传递了缓冲区。@Bergi感谢您的回复,我刚刚意识到,utf-8中该字符的缓冲区是[194164],而ascii中该字符的缓冲区是[164]为什么是社区维基?这是一个非常好的答案。@Bergi:嘿,我也不会写不好的答案!=D事实上,这是因为我厌倦了收到代表通知。啊,我刚刚学会了在顶部栏中保持不变的绿色pin,从不点击它。在我最近胖指它之前,计数达到了5位数:谢谢你的精彩解释这是一个非常好的答案。@Bergi:嘿,我也不会给出不好的答案!=D这实际上是因为我厌倦了收到销售代表通知。啊,我刚刚学会了在顶部栏中保持不变的绿色pin,从不点击它。在我最近胖指它之前,计数达到了5位数:谢谢你的好意解释