pageExecute跳转失败因Webman未自动输出HTML表单,需手动捕获返回内容并用response()->html($html)包装;异步通知验签失败多因未读取php://input原始数据、密钥错误或参数清洗不当。

Webman里调用pageExecute跳转失败,页面空白或报错
Webman默认不自动输出HTML表单,而支付宝SDK的pageExecute方法依赖echo输出自动提交表单。直接调用会卡在响应体未发送,前端收不到跳转指令。
必须手动捕获返回内容并构造HTTP响应:
- 使用
$request->setReturnUrl()和$request->setNotifyUrl()前,确保URL是完整可访问地址(如https://your.com/pay/notify),Webman路由需已注册该路径 - 调用
$aop->pageExecute($request)后,不要直接echo,而是用response()->html($html)包装返回值 - 若用
yansongda/pay等第三方包,注意其gateway('alipay')->pay()返回的是Support\Response对象,需显式调用send()或转为Webman响应
异步通知notify_url收不到POST数据或验签失败
Webman默认禁用$_POST解析原始body(尤其当支付宝发来的是application/x-www-form-urlencoded但含特殊编码时),导致$_POST为空或字段缺失。
正确做法是读取原始输入流,并交由SDK验签:
立即学习“PHP免费学习笔记(深入)”;
- 在
notify路由处理函数中,用file_get_contents('php://input')获取原始数据,再用parse_str()转为数组(注意:不能依赖$_POST) - 验签前必须过滤掉
sign和sign_type字段,且所有键名小写、值去首尾空格——支付宝回调参数名如out_trade_no、trade_status必须原样传入验签函数 - 确认配置的
alipay_public_key是支付宝后台“公钥”页下载的**支付宝公钥**(不是你上传的那对RSA2公钥),且无换行、无-----BEGIN PUBLIC KEY-----头尾
rsaCheckV1返回false但参数看起来都对
这不是密钥错,大概率是字符编码或签名源字符串拼接逻辑被破坏。Webman中间件或全局json_encode配置可能悄悄修改了原始参数顺序或格式。
关键检查点:
- 验签前打印
ksort($data)后的数组,确认app_id、out_trade_no、trade_status等字段都在,且trade_status值为TRADE_SUCCESS或TRADE_FINISHED(不是success小写) - 避免对
$data做任何json_encode或urldecode——SDK的rsaCheckV1要求原始$_POST级数据 - 如果用了
yansongda/pay,别调verify()前自己array_map('urldecode', $_POST),它内部已处理;否则会双重解码导致验签失败
支付成功后订单状态没更新,或重复处理回调
Webman是常驻内存模型,没有传统PHP-FPM的“一次请求一销毁”机制,数据库连接、Redis连接复用更频繁,但notify接口的幂等性控制反而更容易被忽略。
必须强制加锁或查库判重:
- 收到回调第一件事:用
out_trade_no查本地订单,若状态已是paid,直接返回success,不再往下走 - 更新订单时用
WHERE status = 'unpaid'条件更新,避免并发请求同时修改同一订单 - 不要依赖
sleep()或usleep()防并发——Webman协程下无效,且违反HTTP超时规范 - 支付宝可能在几秒内重发多次通知,务必记录每次
notify的原始sign和timestamp到日志,用于排查是否真重复



















