调用第三方接口算签名时,最经典的一类 bug 是"我算的签名和服务端对不上",排查到最后往往是 URL 编码的口径不一致——同一个空格,有的库编成 %20,有的编成 +。
%20 与 + 的来源
两者都是空格,但属于不同规范:application/x-www-form-urlencoded(表单提交)规定空格编码为 +;RFC 3986(URI 规范)规定空格编码为 %20。不同语言的默认行为不同:JavaScript 的 encodeURIComponent 输出 %20,PHP 的 urlencode 输出 +。
空格编码对照: 表单口径(form-urlencoded) → a+b URI 口径(RFC 3986) → a%20b
签名串为什么不一致
接口签名通常要求"按指定规则编码后拼接再哈希"。排查顺序:① 确认空格口径(%20 还是 +);② 确认保留字符(:、/、?、& 等是否被编码);③ 确认参数排序与大小写。任何一步不一致,哈希结果就完全不同。
Q:中文参数一定要编码吗?
URL 规范只允许 ASCII 字符,中文必须百分号编码(如 中文 → %E4%B8%AD%E6%96%87),否则浏览器行为不可预期。
Q:完整 URI 编码是什么?
编码时保留 :/?#&= 等结构字符,只编码参数值部分,适合给整条链接做编码的场景。
提示
对不上签名时,用 URL 编码工具把双方待签名串分别编码对比,差异一目了然。
