微信支付验签失败主因是xml被框架自动解析,须用file_get_contents('php://input')原始读取;统一下单失败多因参数空值、排序错误或ip不实;jsapi签名需前后端url完全一致;沙箱验签须用沙箱密钥而非正式密钥。

微信支付回调验签失败:notify_url 接收后验签总返回 false
最常见原因是微信发来的 XML 数据被 ThinkPHP5 的 input() 或自动 JSON 解析干扰了原始内容。微信回调是纯 POST XML,不是 JSON,也不是表单数据。
必须用 file_get_contents('php://input') 原始读取,再用 simplexml_load_string() 解析,不能走 $this->request->post() 或 input('post.')。
- 在控制器中禁用任何中间件对 POST 数据的预处理(尤其是 json、form 表单解析类中间件)
- 回调入口方法开头立即执行:
$xml = file_get_contents('php://input');,然后$data = (array)simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA); - 注意:微信返回的
<code>return_code和<code>result_code是两个层级,前者表示通信是否成功,后者才表示业务是否成功,别只看一个 - 验签前确保
$data['sign']存在且未被转义或截断(如被 nginx 或 PHP 配置自动过滤特殊字符)
统一下单 unifiedOrder 返回 INVALID_REQUEST 或 MISSING_PARAMETER
ThinkPHP5 本身不参与签名计算,但容易在组装参数时出错——特别是字段名大小写、空格、键顺序、非必填字段留空等细节。
微信要求签名字符串必须按字典序升序拼接(key=value 形式),且所有参与字段值不能为空字符串('')、null 或未定义;空值字段应直接剔除,不能传 'attach' => ''。
- 使用
ksort($params)排序后拼接,不要用asort或手动写死顺序 -
spbill_create_ip必须是真实客户端 IP(不是服务器内网 IP),可用$this->request->ip()获取,但需确认没被代理污染(检查X-Forwarded-For是否可信) -
notify_url必须是公网可访问的完整 URL(https 开头),且域名已配置在商户平台白名单中;本地开发用 ngrok 调试时,每次生成的新域名都要重新配置 - 签名密钥(
key)必须和微信商户平台「API安全」里设置的一致,且不能有多余空格或换行
JSAPI 支付前端调不起 chooseWXPay:提示 invalid signature
这不是后端签名错,而是前端调用 wx.config 时传入的签名和当前页面 URL 不匹配。ThinkPHP5 的路由可能造成 URL 动态变化,而签名是基于「当前浏览器地址栏完整 URL」生成的。
例如访问 /pay/order/123,但实际渲染页面由 index/index 控制器输出,后端签名却用了 /index/index 这个路径,必然失败。
- 前端 JS 中
location.href.split('#')[0]取到的 URL 必须和后端签名时使用的$url完全一致(协议、域名、端口、路径、查询参数) - ThinkPHP5 默认开启 URL 大写转换(
url_convert),若路由含大写字母(如/Pay/Order),实际请求 URL 是小写,但Request::url()可能返回大写形式,需统一转小写再签名 -
nonceStr和timestamp必须和签名时用的一致,不能前端自己生成一套、后端又生成一套 - 确认公众号 JS 接口安全域名已在微信公众平台正确配置(不含
http://,只填example.com)
沙箱环境调试时 getSignKey 接口返回 SYSTEMERROR
微信支付沙箱的 getSignKey 并非用于日常签名,它只在沙箱下单/回调时用来替换正式密钥做模拟验证。但很多人误以为要先调它才能用沙箱,其实只要商户号开通沙箱、且请求地址换成沙箱网关即可。
真正要改的是请求 URL:https://api.mch.weixin.qq.com/sandboxnew/pay/unifiedorder,而不是正式地址;同时 sign 计算仍用正式密钥,但微信沙箱服务会用沙箱密钥反向验证。
- 沙箱密钥需主动调用
getSignKey获取一次,存下来用于本地验签(比如回调验签时),但下单请求的签名仍用正式key - 沙箱接口响应里的
pay_sign字段是沙箱生成的,前端chooseWXPay用它没问题;但后端验签时必须用沙箱密钥,否则失败 - 沙箱环境不支持 JSAPI 的
prepay_id直接唤起支付,需确保测试用的微信号已绑定商户号且开通了沙箱权限
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











