hmac.new() 的 key 和 msg 参数必须是 bytes 类型,str 需显式编码(通常为 utf-8),否则报 typeerror;digest() 返回字节,hexdigest() 返回十六进制字符串,需按 api 要求选用。

hmac.new() 的 key 和 msg 参数必须是 bytes 类型
Python 的 hmac.new() 不接受字符串直接传入,传 str 会报 TypeError: key: expected bytes or bytearray, but got 'str'。必须显式编码,且编码方式要和 API 文档约定一致(通常是 UTF-8)。
常见错误写法:hmac.new("secret", "data", digestmod=hashlib.sha256) —— 这里两个字符串都没转 bytes,直接崩溃。
正确做法:
-
key用bytes:比如b"my_secret"或"my_secret".encode("utf-8") -
msg同样需是bytes:原始请求体(如 JSON 字符串)先.encode("utf-8"),不要用json.dumps()后不编码 - 如果密钥来自环境变量或配置文件,读出来是
str,务必立刻.encode()
签名结果要用 hexdigest() 还是 digest()?看 API 要求
很多 API 文档明确要求 “hex-encoded SHA256 HMAC”,这时必须用 .hexdigest();少数要求原始二进制(比如 Base64 编码前),才用 .digest()。混淆会导致验签失败,且服务端通常不返回具体原因。
典型场景对比:
- 币安 API:要求
hex,header 中传X-MBX-APIKEY+signature字段值为hmac.new(...).hexdigest() - 某些内部系统:要求
base64.b64encode(hmac.new(...).digest()).decode() - 错误示例:用
digest()得到 32 字节 raw bytes,直接塞进 header 会变成乱码或被截断
构造 msg 时顺序和格式必须和服务端完全一致
HMAC 签名本质是“对确定字节流做哈希”,只要服务端拼接规则和你不一样,签名就必然不匹配。常见不一致点:
- 是否包含 query string?有些 API 要把
?a=1&b=2拼在 msg 里,有些只签 body - body 是否标准化?POST JSON 请求,服务端可能要求
json.dumps(data, separators=(',', ':'))(去空格),而你用了默认缩进格式 - 时间戳字段名和格式:比如服务端要求
timestamp=1712345678901(毫秒级 int 字符串),你传了"timestamp": 1712345678901在 JSON 里,但没把它单独抽出来拼进 msg - 是否按字母序排序参数?GET 请求带多个参数时,部分 API 强制要求先对 key 排序再拼接
验证端(服务端)用的 hash 算法和你必须完全一致
别想当然认为 “SHA256 就是 SHA256”。hmac.new(key, msg, digestmod=hashlib.sha256) 是标准写法,但有人误写成 hashlib.sha256(key + msg) —— 这不是 HMAC,是简单拼接哈希,结果完全不同。
还要注意:
- 确认服务端文档写的确实是
HMAC-SHA256,不是HMAC-SHA512或MD5 - Python 3.9+ 支持
hmac.digest()快速函数,但参数顺序是(key, msg, digest),和new().digest()行为一致,可安全替换,但别混用旧写法 - 调试时,把你的
key、msg、最终hexdigest()全部 print 出来,和服务端日志(如有)逐字节比对,比猜快得多
hmac 调用本身,而是你构造 msg 的那几行代码 —— 多一个空格、少一个参数、时间戳单位错位,都会让签名失效,而且问题现象就是“Invalid signature”,没有任何提示指向哪错了。大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











