
收不到支付回调,八成不是代码写错了,而是请求压根没到你的服务器——先查访问日志,再看原始输入流,最后验签。
为什么 $_POST 为空或数据不全
支付宝、微信、苹果等平台的异步通知都不走标准表单编码,$_POST 依赖 Content-Type: application/x-www-form-urlencoded,而它们实际发的是裸 POST body(XML 或 JSON 字符串),PHP 不会自动解析进 $_POST。尤其当 fund_bill_list 含 JSON、receipt-data 是长 Base64 时,框架或 PHP 配置还可能截断或转义。
- 必须用
file_get_contents("php://input")一次性读取原始请求体,且只能读一次 -
$HTTP_RAW_POST_DATA在 PHP 7.0+ 已废弃,且默认关闭,别用 - ThinkPHP/Laravel 等框架里,避免
$this->request->post(),改用$this->request->getRawInput()或等效方法 - 读完立刻记日志:
file_put_contents('notify.log', date('Y-m-d H:i:s') . "\n" . $raw . "\n---\n", FILE_APPEND)
回调 URL 不可达的常见硬伤
微信和支付宝服务器发不出去,或者发出去了但被拦在半路,比代码逻辑错误更难察觉。
- URL 必须是完整 HTTPS 地址,不能带端口(如
:8080)、不能是localhost或内网 IP - 域名需已备案(国内云主机强制要求),SSL 证书必须有效——用
https://www.sslshopper.com/ssl-checker.html验证 - Nginx/Apache 的
access.log里完全查不到来自api.mch.weixin.qq.com或notify.alipay.com的记录,说明请求根本没进来 - 检查防火墙、安全组、WAF(如腾讯云 Web 应用防火墙)是否拦截了 POST 请求或特定 User-Agent
验签前就失败?先确认数据格式和字段名
签名验证失败,未必是密钥或算法错了,很可能是数据还没“对上号”就进了验签流程。
- 微信回调是 XML,得先
simplexml_load_string($xml)再转关联数组,json_decode(json_encode($data), true)是稳妥做法 - 支付宝回调参数含下划线(如
out_trade_no),框架若自动转成驼峰(outTradeNo),验签必挂——字段名必须原样保留 - 苹果回调的
receipt-data要 Base64 解码后才能验,且长度要 >100 字符,否则直接拒掉 - RSA2 公钥必须是 PEM 格式(以
-----BEGIN PUBLIC KEY-----开头),别把.crt文件全文当公钥用
返回 success 太慢或带多余输出
支付平台只认纯文本 success,多一个空格、换行、BOM 头、echo 前的 warning、var_dump 残留,都会导致重试甚至永久失败。
- 验签通过后第一件事:清空输出缓冲
ob_end_clean(),关闭所有调试输出 - 立即
echo 'success',然后exit或die,不要做数据库更新、发消息、调 API - 业务逻辑(如改订单状态)必须扔进异步队列、写入临时表后由定时任务处理,或用
fastcgi_finish_request()提前结束响应 - 别依赖
return_code或result_code就认为成功——微信回调里这两个字段只是通信层状态,trade_state才是真实支付结果
最常被忽略的是:回调地址本身在支付平台后台填错了,或者改了 Nginx 配置但没 reload;还有就是本地测试时用 curl -X POST 模拟,却忘了加 -H "Content-Type: text/xml" 或 -d @notify.xml,导致连原始数据都读不到。这些地方卡住,比算法出错更难定位。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











