Node.js 十六进制入口校验:Buffer.from没有报错,为什么尾部字节已经不见了
接口接收一个十六进制标识,代码用Buffer.from转换成字节,没有抛出异常,于是继续查询。问题是,转换函数可能只保留有效前缀;提交的标识与实际使用的字节已经不同。对需要完整输入的场景,必须先定义允许的文本,再执行转换,不能把“得到一个Buffer”当成全部验收条件。
本例在Linux、Node.js v24.19.0实跑,使用.mjs文件与内置模块,无需安装第三方包。所有数据都在内存中构造,不访问网络、不读取凭据,也不修改外部服务。文档以官方说明核对,输出来自这里标明的具体运行版本。
AI生成的概念示意图:成对的小色块通过入口,末尾一块残缺色片停在检查门外,表示完整字节需要两个合法半字节;不是真实软件界面或运行截图。
完整程序与实际输出
保存为demo.mjs,执行node demo.mjs。代码与输出分列如下。
import { Buffer } from 'node:buffer';
import assert from 'node:assert/strict';
function requireHex(text) {
if (typeof text !== 'string' || text.length === 0 ||
text.length % 2 !== 0 || /[^0-9a-fA-F]/.test(text)) {
throw new TypeError('expected nonempty even-length hex');
}
return Buffer.from(text, 'hex');
}
for (const text of ['c0ffee', 'c0ffeg', 'c0ffe', 'c0 ff', 'abc\n', '']) {
const loose = Buffer.from(text, 'hex').toString('hex');
let strict;
try { strict = requireHex(text).toString('hex'); }
catch (error) { strict = error.name; }
console.log(JSON.stringify({ input: text, loose, strict }));
}
assert.equal(requireHex('C0FFEE').toString('hex'), 'c0ffee');
assert.throws(() => requireHex('c0ffe'), TypeError);
assert.equal(requireHex('000f').length, 2);
console.log('leading zero bytes:', requireHex('000f').length);本次实际标准输出:
{"input":"c0ffee","loose":"c0ffee","strict":"c0ffee"}
{"input":"c0ffeg","loose":"c0ff","strict":"TypeError"}
{"input":"c0ffe","loose":"c0ff","strict":"TypeError"}
{"input":"c0 ff","loose":"c0","strict":"TypeError"}
{"input":"abc\n","loose":"ab","strict":"TypeError"}
{"input":"","loose":"","strict":"TypeError"}
leading zero bytes: 2先观察宽松转换留下什么
c0ffee得到完整的三字节内容,作为正常对照。c0ffeg含非法字符g,输出只剩c0ff;c0ffe虽全是十六进制字符,末尾却只剩半个字节,同样得到c0ff。两种不同错误输入因此可能被转换成同一份较短数据。
c0 ff遇到空格只留下c0,abc后跟换行则只留下ab。输出使用JSON表示原输入,使换行能够被看见。Buffer.from在这些样本中没有报告失败,结果确实可用,但“可用的前缀”并不符合本例“整串完整编码”的输入合同。
把四项条件放在转换之前
requireHex先要求字符串,再拒绝空串、奇数长度和任何非十六进制字符。否定字符类会检查整段文字中是否出现非法字符,包括空格和换行;只有全部条件通过才调用转换函数。它不先trim,也不试图自动补零,所以不会隐式修复调用者传入的标识。
这套规则有意接受大小写字母,最后的断言验证C0FFEE能转成同一份字节。输出小写只是toString选择的显示形式。如果协议还要求统一小写文本,应另加规范写法检查;字节值相同与原文格式相同,是可以分别约定的两个条件。
保住前导零和长度信息
最后一行显示000f有两个字节,前面的零字节确实存在。若先把整串转成普通数值再转回文本,长度信息就可能丢掉,还可能遇到整数精度限制。对于固定长度编号、二进制头部或摘要,直接按字节处理更容易保持原有结构。
示例只要求非空偶数长度,没有规定必须几个字节。真实协议往往还要限制最小和最大长度,甚至要求精确长度;这些限制应在分配大缓冲前执行。不能因为字符都合法,就允许任意大的输入占用服务内存。
错误应到达清晰的业务边界
循环把TypeError转换为可读标签,仅用于展示每个样本的结果;生产函数应把拒绝原因交给统一输入错误处理,不继续拿宽松结果执行查询。若格式允许分组空格或前缀,应先写出明确的解析规则并测试,不能临时删掉所有看不懂的字符。
还应补充纯非法字符、单个字符、完整前导零、非字符串和超长输入测试。通过这些检查只说明文本能按约定还原成字节,不证明内容来自可信发送者,也不验证业务身份。对于认证数据,仍需独立执行对应协议的认证与授权步骤,本例未使用任何真实认证材料。
参考资料与验证记录
官方资料核验于2026年10月3日。本次完整程序退出码为0,标准错误为空。


