验证失败主因是signature校验不通过:需用后台token、timestamp、nonce三者按字典序排序拼接后sha1,结果须与请求中signature完全一致,token须严格匹配(大小写、空格、标点均敏感)。

怎么验证微信服务器发来的 GET 请求
验证失败是接入第一步最常见的卡点,本质不是代码写错,而是微信和你对“同一串字符”是否一致的判断出问题。
微信会向你配置的 URL 发起 GET 请求,附带 signature、timestamp、nonce 和 echostr 四个参数;你要用后台填的 TOKEN、timestamp、nonce 三者排序后拼接再 SHA1,结果必须和 signature 完全相等,才能返回 echostr。
-
TOKEN必须和公众号后台「服务器配置」里填的一模一样——区分大小写、不能有空格、不能用中文标点 - 排序必须用
sort($arr, SORT_STRING),不是SORT_NUMERIC;比如"123"和"23"字典序下是"123" ,数值序则相反 - 拼接前不要加空格或换行,直接
implode('', $arr),否则 SHA1 结果必然不匹配 - 验证通过后必须
echo $echostr并立刻exit,后续任何输出(包括空白符、BOM)都会导致微信解析失败
为什么 php://input 拿不到 POST 消息
用户发消息后,微信会以 XML 格式、POST 方式推送到你的 URL。但很多人发现 $_POST 是空的,file_get_contents('php://input') 也读不到内容——这通常不是微信没发,而是 PHP 或服务器拦住了。
- 确保 Web 服务器(如 Nginx/Apache)没有禁用
php://input;Nginx 常见错误是配了client_max_body_size过小,或用了fastcgi_pass但未透传原始 body - PHP 的
enable_post_data_reading = On(默认开启),但若脚本开头调用了http_response_code()或header()前就尝试读取php://input,某些 SAPI 下会失败 - 不要用
$HTTP_RAW_POST_DATA(PHP 5.6+ 已废弃且默认关闭),只认file_get_contents('php://input') - 读到内容后,务必用
simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)解析,否则 CDATA 里的换行、特殊符号会被转义丢弃
回复图文消息时 XML 构造总被微信忽略
图文消息不是把多个文本拼一起就行,微信对 MsgType、ArticleCount、Articles 结构、甚至字段顺序都有硬性校验,错一个就静默丢弃。
立即学习“PHP免费学习笔记(深入)”;
-
MsgType必须是"news"(字符串,非数字),且整个 XML 中只能有一个MsgType节点 -
ArticleCount必须是数字(如2),不能是字符串"2",否则微信认为格式非法 -
Articles下每个item必须包含Title、Description、PicUrl、Url四个字段,缺一不可;PicUrl必须是可公开访问的 HTTPS 地址(HTTP 会被微信拦截) - 最多支持 8 篇,超过数量的
item不会被截断,而是整条消息失效 - 所有 XML 必须 UTF-8 编码,且不能含 BOM;建议用
mb_convert_encoding($str, 'UTF-8', 'auto')预处理标题/描述
为什么本地测试通,上线后验证总失败
最典型的陷阱:你以为在跑 PHP,其实微信请求根本没进你的 PHP 脚本。
- 确认域名已备案 + 服务器强制 HTTPS —— 微信从 2023 年起拒绝所有 HTTP 回调,哪怕你 Nginx 301 跳转也不行,必须原始请求就是 HTTPS
- 检查 Web 服务器是否把
.php后缀强制重写或过滤了;有些主机商默认屏蔽带echostr参数的请求(误判为扫描) - 用
curl -v "https://your.com/wechat.php?signature=xxx×tamp=yyy&nonce=zzz&echostr=aaa"在服务器本地实测,看是否真能拿到响应,排除 CDN 或 WAF 拦截 - 日志里查
$_SERVER['REQUEST_METHOD']和$_GET是否为空——如果为空,说明请求压根没路由到 PHP,别在逻辑里找 bug











