社区积分回调签名校验总失败,最后发现是 `ksort` 和 `json_encode` 的锅
上周接了个需求:把社区的发帖、回帖、积分三个接口串起来,用户在我们CMS发帖,同步到社区,社区回帖再回写到CMS,积分两边实时对齐。听起来就是几个HTTP调用,实际搞了四天。
最阴的是积分回调的签名校验。社区那边文档写的是"参数按key升序拼接,MD5签名",我照做了,本地通,一上测试环境就报 `sign_invalid`。抓包对比,参数一样,顺序一样,签名就是不对。
排查两小时,发现社区用的 `ksort($params, SORT_STRING)`,我直接 `ksort($params)`。PHP默认 `SORT_REGULAR`,数字字符串 `"10"` 和 `"2"` 排序结果跟 `SORT_STRING` 不一样。就这一个参数,签名对不上,回调全被拒,积分流水堆了七百多条待处理。
更坑的是 `json_encode`。回帖内容里有emoji,社区存的是UTF-8,我这边MySQL也是 `utf8mb4`,按说没问题。但签名时社区把body做了 `json_encode($data, JSON_UNESCAPED_UNICODE)`,我默认encode带转义,`\u4f60\u597d` 和 `你好` 签出来完全不同。后来干脆约定:所有参与签名的字段先 `json_encode` 再 `hash_final`,编码选项写死进SDK里。
发帖接口倒是顺,但有个设计失误。我图省事用了同步调用,用户点发布,等社区返回 `post_id` 才写本地库。社区那边偶尔502,我这边前端转圈十秒然后报错,用户疯狂重试,同一帖子发了四条。后来改成本地先落草稿状态,异步队列去同步社区,成功再改 `published`,失败走人工审核。用户体验没差,我这边稳多了。
回帖同步回CMS时踩了并发坑。社区回调通知"有新回复",我查社区接口拉详情,同时另一个进程也在拉,两条回复插进了同一条父评论下,树形结构直接乱套。最后加了唯一索引 `(community_reply_id)`,回调里先 `INSERT IGNORE`,存在就跳过,日志里记条 `duplicate_reply_skipped`,至少不崩数据。
现在三个接口跑了一周,积分对账误差为零。但回头看,最耗时间的不是业务逻辑,是这些"约定俗成"的细节:排序规则、编码选项、时区统一(社区用UTC,我这边东八,时间戳比对差点又翻车)。文档不会写这么细,对接两个系统就是互相猜,猜错了就凌晨两点抓包。
有也在搞多系统对接的老哥吗?你们签名校验一般怎么约定,直接上RSA还是MD5够用?我这边现在MD5+密钥轮转,感觉迟早要换。

