项目框架从tp5升级到tp6,原来的支付宝支付,改用
yansongda/pay
,使用沙箱模拟支付流程基本ok,切换正式参数,频繁报错,每次接入支付都花费很长时间调试。特此记录,以供以后遇到同样问题快速解决!网上说
subject
和body
传递的中文改成英文依旧报错,那就不是编码问题、之后又遇到检验RSA2
密钥是否匹配问题,根据云排查可能是公钥私钥之类配置错误。重新生成配置。重新生成应用公私钥,公钥上传对应应用上,并获取支付宝公钥和应用私钥配置到支付宝配置文件。终于可以唤醒支付宝支付了,支付完成发现并没有回调成功,经过自助工具调式,发现服务器返回500,发现有代码有问题,处理完毕,整个支付流程ok。支付宝配置文件:
config/alipay.php
,其中app_id,支付宝公钥,应用私钥,网关,编码格式,签名方式
,全部和旧的支付配置一样。
<?php
// +----------------------------------------------------------------------
// | 支付宝支付设置
// +----------------------------------------------------------------------
return [
'app_id' => "20191219600502xx",//应用ID
'notify_url' => env('app.host')."/api/notify/alipay",//异步通知地址
'return_url' => env('app.host')."/upgrade", //同步跳转
'ali_public_key' => "xxx", //支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
'private_key' => "xxx",//商户私钥,您的原始格式RSA私钥
'charset' => "UTF-8", //编码格式
'sign_type'=>"RSA2", //签名方式
'gatewayUrl' => "https://openapi.alipay.com/gateway.do",//支付宝网关
//如果是沙箱模式用这个支付宝网关:'https://openapi.alipaydev.com/gateway.do',
'log' => [
'file' => app()->getRuntimePath() .'api'.DIRECTORY_SEPARATOR.'log'.DIRECTORY_SEPARATOR.date('Ymd').DIRECTORY_SEPARATOR.'alipay.log',//日志文件路径
'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug
'type' => 'single', // optional, 可选 daily.
'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
],
'http' => [
'timeout' => 5.0,
'connect_timeout' => 5.0,
// 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
],
//'mode' => 'dev', // 开启此参数,将进入沙箱模式
];
在微信公众号环境跳浏览器打开唤醒支付宝支付,然后跳到错误页面:
在订单结束,进入支付页面的时候出现
错误代码 invalid-signature 错误原因: 验签出错,
建议检查签名字符串或签名私钥与应用公钥是否匹配,网关生成的验签字符串为:
alipay_sdk=alipay-sdk-java-4.8.10.ALL&app_id=2016102600763118&biz_content={"out_trade_no":"xxx","total_amount":"100","subject":"xxx","body":"xxx","product_code":"FAST_INSTANT_TRADE_PAY"}&charset=utf-8&format=json&method=alipay.trade.page.pay¬ify_url=xxx&return_url=xxx&sign_type=RSA2×tamp=xxx&version=1.0
错误代码 invalid-signature
秘钥工具生成秘钥:
支付宝开放平台开发助手,根据系统下载软件,安装完成后,选择RSA2,PKCS1秘钥格式,
然后生成秘钥(应用公私钥)。秘钥匹配验证应用公私钥是否匹配。
一、应用公钥(public key)、应用私钥(private key)自己用工具生成并上传公钥到支付宝商户后台对应的app_id应用。
二、支付宝公钥为支付宝提供,支付宝传递数据用支付宝私钥加密,用户用支付宝公钥解密,
用户传递数据用应用私钥加密,支付宝用上传的公钥解密。
三、登录支付宝商户后台,根据app_id找到对应的应用,上传应用公钥。并获取支付宝公钥,和应用私钥一起写入配置文件
生成秘钥(应用公私钥)
验证应用公私钥
根据app_id查看支付宝公钥和应用公钥
开发工具 > 支付宝开放平台开发助手 > 支付宝公共开发文档
历史接口接入指南 > 签约与审核
开发工具 > 云排查:https://opensupport.alipay.com/support/knowledge/01/201602472811
自助工具调试(需登录),支付请求返回错误信息和异步回调问题排查https://opensupport.alipay.com/support/tools/cloudparse?ant_source=openmonitor
自助工具调试:请求问题排查和异步回调排查路由配置:
//支付必须登录状态下
Route::group('pay', function () use($version){
Route::any('wechat',"{$version}.Pay/wechat");//微信支付
Route::any('alipay',"{$version}.Pay/alipay");//阿里支付
})->middleware('Jwt');
//回调
Route::group('notify', function () use($version){
Route::any('wechat',"{$version}.Pay/wechat_notify");//微信支付回调
Route::any('alipay',"{$version}.Pay/alipay_notify");//阿里支付回调
});
支付逻辑代码:
/**
* 支付宝支付
* @return array|mixed
*/
public function alipay(){
$uid = 0;//当前登录账户的ID
$user = User::where(['id'=>$uid])->find();
if($user->vip){
$order_data = Order::where(['userId'=>$uid,'status'=>0])->find();//未支付订单
if(empty($order_data)){
$order_data[ 'uid'] = $uid;
$order_data[ 'mobile'] = $user->mobile;
$order_data[ 'order_sn'] = time();//订单号
$order_data[ 'create_time'] = time();
$order_data[ 'order_money'] = config('system.upgrade_money')*100;
//升级费用单位元,写入数据库单位为分
$order_id = Order::insertGetId($order_data); //订单入库
}
if($order_id)
return Pay::alipay(config('alipay'))->wap( [
'out_trade_no' => $order_data[ 'order_sn'],//本地订单号
'total_amount' => $order_data[ 'order_money']/100,//支付金额,单位元
'subject' => '升级会员',//支付界面显示标题
])->send();
}
}
回调处理代码:
public static function alipay_notify()
{
$alipay = Pay::alipay(config('alipay'));
try{
$data = $alipay->verify(); // 是的,验签就这么简单!
// 请自行对 trade_status 进行判断及其它逻辑进行判断,
// 在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,
// 支付宝才会认定为买家付款成功。
// 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号;
// 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额);
// 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no
// 这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email);
// 4、验证app_id是否为该商户本身。
// 5、其它业务逻辑情况
if(in_array($data['trade_status'],['TRADE_SUCCESS','TRADE_FINISHED'])){
$order_sn = htmlspecialchars($data['out_trade_no']);
$order = Order::where(['orderSn'=>$order_sn])->find();
if(empty($order)){//订单不存在
trace("订单{$order_sn}不存在", 'info');
}
if(!$order->status) {//未支付
if (bccomp($order->order_money/ 100, $data['total_amount'], 2) != 0) {
//实际支付与订单金额不符
trace("订单{$order_sn}金额不符合", 'info');
exit('FAILE');
}
//此处编写回调处理逻辑
//返回返佣数据,先查数据库有没有生成,若生成则忽略,没生成则生成
//防止多次回调生成多余数据
//更新订单状态
//更新用户成会员
//未支付订单清除
}
}
} catch (\Exception $e) {
trace('alipay_notify', $e->getMessage());
}
return $alipay->success()->send();
}
网友评论