微信支付回调验签失败主因是配置错误:notify_url需公网https且无参数,证书须放storage/app/certs/并设600权限,sdk中cert_path和key_path用绝对路径;laravel需禁用trimstrings中间件防header过滤。

微信支付回调验签总失败?别急着改代码,先检查 notify_url 和证书路径
Laravel 接入微信支付最常卡在回调验签失败,错误通常是 INVALID_SIGNATURE 或 MISSING_PARAM。这不是 SDK 本身的问题,而是配置没对齐。
-
notify_url必须是公网可访问的 HTTPS 地址,且不能带查询参数(如https://xxx.com/pay/callback?from=wechat会失败) - 微信支付 V3 接口要求传
apiclient_cert.pem和apiclient_key.pem,这两个文件必须由商户平台下载后,**直接放在storage/app/certs/下,且权限为 600**(Laravel 进程需有读取权限) - SDK 初始化时传的
cert_path和key_path必须是绝对路径,推荐用storage_path('app/certs/apiclient_cert.pem'),别用相对路径或public_path() - 微信回调请求头里带
Wechatpay-Serial,Laravel 默认会过滤掉带连字符的 header,需在App\Http\Kernel的$middleware中确认没启用TrimStrings或类似中间件干扰原始 header
Laravel 10+ 用 wechatpay-apiv3 SDK 怎么发统一下单?关键在 HttpClient 配置
官方推荐的 wechatpay-apiv3 是纯 PHP SDK,不依赖 Laravel,但和 Laravel 的 Http facade 冲突——它自己封装了 cURL,不能复用 Laravel 的全局 HTTP 设置。
- 下单前必须调用
WechatPayHttpClient::create(...)构造客户端,其中merchantId、serialNo、privateKey缺一不可;serialNo不是证书序列号,而是微信商户平台「API 安全」页里显示的「证书序列号」(32 位十六进制字符串) - 下单参数中
notify_url必须和后台配置完全一致(包括末尾斜杠),amount单位是分,description不能含 emoji 或控制字符,否则返回PARAM_ERROR - 不要手动拼接 JSON body,用 SDK 提供的
Json::encode($data),否则中文乱码或空格差异会导致签名失败 - 调用
$client->post('/v3/pay/transactions/jsapi', $body)后,响应是标准 JSON,直接json_decode($response->getBody()->getContents(), true)即可,不用再解密(V3 接口已取消响应加密)
前端 JSAPI 支付唤起失败?检查 prepay_id 签名和域名白名单
后端返回了 prepay_id,但前端调用 WXJSSDK.chooseWXPay 报错 invalid signature,90% 是签名环节出了问题。
- 签名字段必须严格按顺序:
appId、nonceStr、package、signType、timeStamp,少一个、顺序错、大小写错都不行 -
package值是字符串prepay_id=xxx,不是数组,不是 JSON,不能加引号 - 签名用的
nonceStr和timeStamp必须和后端统一下单时传给微信的一致(很多同学前端自己生成一套,后端又生成一套,必然失败) - 公众号 JSAPI 支付的调用域名,必须在微信公众号后台「公众号设置 → 功能设置 → JS 接口安全域名」里配置,且只能填一级域名(如
pay.example.com,不能填https://pay.example.com)
沙箱环境能跑通,正式环境一直 SYSTEMERROR?重点查 sub_mch_id 和子商户资质
如果你接入的是服务商模式(比如帮客户代商户收款),SYSTEMERROR 往往不是代码问题,而是资质或参数错位。
- 正式环境必须用正式证书,沙箱证书无效;且
sub_mch_id必须是微信分配的真实子商户号,不能是测试号 - 服务商调用统一下单接口时,
sub_mch_id要放在请求 body 顶层,同时headers里还得带Authorization: WECHATPAY2-SHA256-RSA2048 ...,这个签名要包含sub_mch_id字段(SDK 默认不包含,得手动 patch 或换用支持服务商模式的封装库) - 子商户必须已在微信服务商平台完成「产品签约」,且开通了 JSAPI 支付权限;仅签约不等于可用,还得在「子商户管理 → 权限配置」里手动勾选
- 调试时别只看返回体,用微信支付「商户平台 → 交易中心 → API 安全 → 查看调用日志」,那里能看到真实错误原因(比如
sub_mch_id not exist)
微信支付正式环境的限制比文档写的更死板,尤其是服务商场景下,sub_mch_id、证书、权限、签名字段这四样,漏一个就卡住,而且错误码统一返回 SYSTEMERROR,得靠日志反推。











