微信JSAPI支付回调PHP怎么接收_处理JSAPI异步通知数据方法【指南】
技术百科
雪夜
发布时间:2026-01-01
浏览: 次 微信JSAPI支付回调需用file_get_contents('php://input')读取原始XML,校验sign签名后更新订单状态,返回严格格式SUCCESS XML并确保HTTP 200响应。
微信JSAPI支付回调PHP怎么接收原始XML数据
PHP默认不会自动解析微信发来的XML格式通知,$_POST 是空的,file_get_contents('php://input') 才是唯一可靠入口。很多开发者卡在这一步,误以为要靠 $_GET 或表单提交方式接收。
- 微信服务器发起的是
POST请求,且Content-Type为application/xml,不是application/x-www-form-urlencoded -
$_POST只处理表单编码数据,对纯 XML 无响应,必须手动读取原始请求体 - 务必在脚本开头加
header('HTTP/1.1 200 OK'),否则微信会反复重试(最多5次)
怎么安全解析并验证JSAPI异步通知的XML
不能直接用 simplexml_load_string() 后就信任所有字段——微信通知可能被伪造,必须校验签名。签名字段 sign 是对除 sign 外所有字段按字典序拼接后,用商户密钥 key 做 MD5 计算得出。
- 先用
simplexml_load_string($rawData)解析,再转成关联数组(注意asXML()和属性处理) - 剔除
sign字段后,对剩余字段按键名升序排序,拼成key1=value1&key2=value2格式 - 末尾追加
&key=YOUR_MCH_KEY,再strtoupper(md5($string)) - 对比结果与原始
sign是否一致,不一致立即返回fail
function getSignFromXml($xmlString, $mchKey) {
$data = json_decode(json_encode(simplexml_load_string($xmlString, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
if (!isset($data['sign'])) return false;
unset($data['sign']);
ksort($data);
$string = http_build_query($data, '', '&', PHP_QUERY_RFC3986);
$string
= str_replace(['+', '%20'], [' ', '+'], $string); // 修复 http_build_query 对空格的编码问题
$string .= '&key=' . $mchKey;
return strtoupper(md5($string));
}
收到通知后怎么更新订单状态并避免重复处理
微信可能因网络问题多次推送同一笔通知,PHP脚本必须具备幂等性。不能只靠数据库 UPDATE,得先查、再判、再改,且整个过程需加锁或依赖唯一业务字段约束。
- 从XML中提取
out_trade_no(你系统生成的订单号),这是唯一可信赖的业务标识 - 查询该订单当前状态:若已是
success,直接返回success;若为pending,才执行状态更新和后续逻辑(如发货、积分发放) - 更新时建议用
WHERE status = 'pending'条件,防止并发场景下重复执行成功逻辑 - 不要在通知处理中调用微信退款、查询等接口——超时风险高,应放入队列异步处理
// 示例:原子化更新订单状态
$sql = "UPDATE orders SET status = 'paid', paid_at = NOW() WHERE out_trade_no = ? AND status = 'pending'";
$stmt = $pdo->prepare($sql);
$stmt->execute([$outTradeNo]);
if ($stmt->rowCount() === 0) {
// 已处理过,直接返回 success
echo ' ';
exit;
}
为什么返回 success XML 还被微信不断重发
表面返回了正确XML,但实际HTTP状态码不是200,或者响应体里混入了空格、BOM头、调试输出,都会导致微信判定失败。这是最隐蔽也最常见的坑。
- 确保脚本开头没有
echo、var_dump、print_r,甚至error_log都可能干扰输出 - 检查PHP文件是否以UTF-8无BOM格式保存(BOM会导致响应头前多出
\xEF\xBB\xBF) - 用
curl -v https://yourdomain.com/notify.php检查响应头和响应体是否干净 - 微信要求返回的XML必须严格符合格式:
,不能多标签、不能少 CDATA
真正稳定的回调处理,核心不在解析多复杂,而在于每一步都做防御性判断,并把“不可信输入”和“不可控网络”当作默认前提。尤其注意 php://input 的一次性读取特性——读完就没了,别在中间 die() 或抛异常后还想再读一次。
# ai
# 微信
# 网络问题
# app
# js
# json
# curl
# String
# 编码
# xml
# 为什么
# php
# 状态码
# echo
# 表单提交
# die
# php脚本
# 退款
# 关联数组
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- 本地php环境出现502错误_nginx或apac
- Win11怎么更改鼠标指针_Windows 11自
- Win11怎么关闭通知中心_Windows11系统
- 如何在 Laravel 中通过嵌套关联关系进行 o
- Win11怎么关闭贴靠布局_Win11禁用窗口最大
- Win10怎样卸载iTunes_Win10卸载iT
- PythonGIL机制理解_多线程限制解析【教程】
- Win11怎么开启游戏模式_Win11优化游戏帧数
- 如何在 Go 中创建包含 map 的 slice(
- 如何使用Golang指针与结构体结合_修改结构体内
- SAX解析器是什么,它与DOM在处理大型XML文件
- Windows10如何更改日期格式_Win10区域
- Win11输入法选字框不见了怎么办_Win11输入
- Windows如何使用注册表查找和删除项?(reg
- Windows10怎么查看系统激活状态_Windo
- Windows10电脑怎么查看硬盘通电时间_Win
- mac怎么退出id_MAC退出iCloud账号与A
- PhpStorm怎么调试PHP代码_PhpStor
- 如何使用Golang搭建本地API测试环境_快速验
- Win11如何设置文件关联 Win11修改特定文件
- Win11怎么关闭开机声音_Win11系统启动提示
- Win10如何卸载自带Edge_Win10彻底卸载
- 如何在Golang中处理模块冲突_解决依赖版本不兼
- Python生成器表达式内存优化_惰性计算说明【指
- Win11怎么更改计算机名_Windows11系统
- 如何用正则表达式精确匹配“start”到“end”
- Windows11如何设置专注助手_Windows
- Win11开机自检怎么关闭_跳过Win11开机磁盘
- 如何在 Go 中正确初始化结构体中的 map 字段
- Windows如何查看和管理已安装的字体?(字体文
- Win11无法拖拽文件到任务栏怎么办_Win11开
- LINUX下如何配置VLAN虚拟局域网_在LINU
- 短链接怎么用php递归还原_多层加密链接的处理法【
- 如何使用Golang开发基础文件下载功能_Gola
- Python与OpenAI接口集成实战_生成式AI
- php下载安装包太大怎么下载_分卷压缩下载方法【教
- php8.4如何配置ssl证书_php8.4htt
- Win11快速助手怎么用_Win11远程协助连接教
- 电脑无法识别U盘怎么办 Windows磁盘管理与驱
- Win11怎么用设置清理回收站_Win11设置清理
- php485在macos下怎么配置_php485
- Drupal 中 HTML 链接被双重转义导致渲染
- c++ atoi和atof函数用法_c++字符数组
- Win11如何开启telnet服务 Win11启用
- LINUX如何删除用户和用户组_Linux use
- php8.4新语法match怎么用_php8.4m
- c++中如何求一个数的平方根_c++ sqrt函数
- 一文教你快速开通网站LOGO图
- Win10怎样清理C盘Steam游戏缓存_Win1
- Win11怎么退出微软账户_切换Win11为本地账

= str_replace(['+', '%20'], [' ', '+'], $string); // 修复 http_build_query 对空格的编码问题
$string .= '&key=' . $mchKey;
return strtoupper(md5($string));
}
QQ客服