laravel 5.5 配置支付宝手机网站支付成败关键在于密钥格式(pkcs1)、密钥来源(ali_public_key须从支付宝后台获取、private_key须去头尾并合并为单行)、回调地址公网可达性——三点任一出错即verify()失败。

直接上结论:Laravel 5.5 配置支付宝手机网站支付,核心不是“装什么包”,而是「密钥格式对不对、ali_public_key 和 private_key 哪儿来、回调地址是否可被公网访问」——这三点错一个,verify() 就会返回 false,后续全白忙。
密钥必须用 PKCS1 格式,且不能换行
支付宝官方工具默认生成的是 PKCS8(Java 兼容),但 yansongda/laravel-pay(v2.x)要求商家私钥是 PKCS1(非 Java 使用)。很多人复制粘贴后验签失败,就是私钥里混入了换行符或空格。
-
private_key必须是纯字符串:去掉-----BEGIN RSA PRIVATE KEY-----和-----END RSA PRIVATE KEY-----,中间所有换行合并成一行 -
ali_public_key不是你自己生成的公钥,而是支付宝后台「查看支付宝公钥」拿到的内容(RSA2 / SHA256),同样要去掉头尾标记、合并为一行 - 用
openssl rsa -in private_key.pem -text -noout可验证是否为 PKCS1;若报错“unable to load Private Key”,说明格式不对
notify_url 和 return_url 必须能被支付宝服务器直连
支付宝沙箱或正式环境发起回调时,不会走你本地的 localhost 或内网 IP。开发阶段最稳妥的方式是用 ngrok 或 localtunnel 暴露接口,而不是配 127.0.0.1 或 192.168.x.x。
-
notify_url是 POST 接口,必须能接收原始 POST 数据(不能依赖 Laravel 的$request->all()直接解析,要用file_get_contents('php://input')或$request->getContent()) -
return_url是 GET 跳转页,用于用户支付完成后前端展示,不参与验签,但路径必须和支付宝后台配置完全一致(包括末尾斜杠、协议 http/https) - 沙箱环境回调可能延迟 1–3 秒,别一没收到就以为失败;正式环境建议加日志记录原始请求体,方便排查
拉起支付返回的是 HTML form,别直接 JSON 返回
Pay::alipay($config)->wap($order) 返回的是完整 <form></form> 字符串,含自动 submit 的 JS。如果后端强行 json_encode(['form_text' => $alipay]) 给前端,再用 $("body").append(data.form_text) 插入,容易因 XSS 过滤或 DOM 解析异常导致表单不提交。
- 正确做法:后端直接
return response($alipay)->header('Content-Type', 'text/html'); - 或者前端用
iframe加载该响应,避免污染当前页面 DOM - 若必须走 API 模式,需手动提取
<input>字段拼成对象,再用 JS 构造 form 提交 —— 但没必要,支付宝明确要求“服务端直出 form”
验签失败时,先检查 mode 和 app_id 是否匹配
沙箱和正式环境的 app_id 完全不同,且 mode => 'dev' 会自动切换网关域名。但很多人把沙箱的 app_id 配到正式配置里,又没开 mode,结果请求发到正式网关却用沙箱密钥验签,必然失败。
- 沙箱
app_id长度为 16 位(如2021000123456789),正式环境是 16 位纯数字但值完全不同 - 确认
config('pay.alipay.mode')值为'dev'时,yansongda/laravel-pay才会使用沙箱网关https://openapi.alipaydev.com/gateway.do - 正式环境务必删掉
'mode' => 'dev',否则请求会被拒绝
最常被忽略的点:支付宝公钥(ali_public_key)和你上传的应用公钥是两回事,前者只用于验签,后者只用于支付宝加密;混淆这两者,验签永远过不了。










