最常卡死在验证不通过、消息收不到、access_token频繁刷新三处:signature校验需严格按字典序排序拼接再SHA1;POST消息必须用php://input读原始XML,不可依赖$_POST;access_token必须用Redis等跨请求强一致性缓存,设7200秒过期。

ThinkPHP6.0 对接微信公众号,最常卡死在验证不通过、消息收不到、access_token 频繁刷新这三处。不是框架不行,而是微信的校验逻辑极严,错一个字符、少一次排序、多一次 $_POST 读取,就静默失败。
signature 总是不匹配?检查排序、拼接、哈希三步是否全对
微信 GET 请求传来的 signature 是用 token、timestamp、nonce 三个字符串字典序排序后拼成一串再 SHA1 得到的——任何环节偏差都会导致比对失败。
- 必须用
sort($arr, SORT_STRING),不能用asort或ksort:后者保留键名顺序,拼接时实际顺序错乱 - 数组必须且仅含三个值:
$token、$timestamp、$nonce;多一个空格、换行、隐藏 BOM 或多余键(比如echostr)都会让sha1(implode('', $arr))结果不同 - 必须用
sha1(implode('', $arr));hash('sha1', ...)默认返回二进制,要加true参数才等效,否则永远不匹配 - 调试时一定要并列打印:
var_dump($signature, sha1(implode('', $arr))),微信不会告诉你哪错了
收到 POST 请求但 $_POST 为空、simplexml_load_string 报错?你读错了数据源
微信所有普通消息(文本、事件、图片)都走 raw XML,不带 Content-Type: application/x-www-form-urlencoded,所以 $_POST 必然为空——这不是 Bug,是设计如此。
公众号运营:文章发布至草稿、样式封面、评论与用户管理、数据统计等。用户要求将 Markdown 发送到公众号草稿、查看阅读量统计或类似后台操作时,使用本技能。
- 唯一正确方式是:
file_get_contents('php://input');$GLOBALS['HTTP_RAW_POST_DATA]已废弃且默认关闭 - 调用
simplexml_load_string前必须执行:libxml_disable_entity_loader(true),否则存在 XXE 漏洞,微信服务器可能拒绝响应 - 解析后字段如
FromUserName、MsgType全是大驼峰,注意大小写;CreateTime是字符串格式数字,回复时需显式转成(string)time() - 回复 XML 时,
Content-Type必须设为text/xml; charset=utf-8,少一个分号或写成utf8都可能被微信丢弃
为什么每次请求都重拉 access_token,还总触发限频?缓存没做对
access_token 是全局凭证,有效期 7200 秒,但每天最多调用 2000 次。它绝不能按请求生成,更不能存在 session 或文件未加锁写入。
立即学习“PHP免费学习笔记(深入)”;
- 不能存在
$_SESSION或$_SERVER:不同请求之间不共享,等于没缓存 - 文件存储必须加锁:
flock($fp, LOCK_EX),否则并发写会损坏 JSON 内容 - Redis 是最优解:
$redis->setex('wx_access_token', 7200, $token),天然支持过期、无竞态 - 每次使用前检查缓存是否存在且未过期,过期判断应基于「缓存写入时间 +
expires_in」,不是拿当前时间戳跟expires_in硬比
真正难的不是写代码,而是理解微信每个环节的“刚性约束”:签名排序必须字典序、消息体必须读原始流、access_token 必须跨请求强一致性缓存。漏掉任意一个,系统就表现得像“完全不通”,但其实只是某一行逻辑卡死了。


















