最近做了一个微信公众号支付 , 使用的是laravel 8 框架 , 使用的是yansongda 2.0 版本,通过composer 下载( composer require yansongda/pay:~2 ),一切就绪后咋们就开始吧!
我遇到的坑就是回调路由无效,当时支付了很多笔,也支付成功了,但是设置的回调方法一点作用都没用,根本不走设置的回调路由这个方法,另外也在微信商户平台也设置过回调路由地址了,并且请求参数回调路由可以走的通,到底怎么回事呢,我们来看看:
下面是当时设置的路由(因为使用的是get方式所以接收不到xml数据):
这是我设置的回调地址:https://xxxxxx.com/api/wxpay/notify
路由设置
$router->get("api/wxpay/notify","LoginPaymentController@notifyCallback");//微信支付回调地址
然后看了日志目录地址(/storage/logs/lumen-2021-11-23.log) , 说接收不到xml数据导致的
[2021-11-23 10:24:27] local.ERROR: INVALID_ARGUMENT: Convert To Array Error! Invalid Xml! {"exception":"[object] (Yansongda\\Pay\\Exceptions\\InvalidArgumentException(code: 3): INVALID_ARGUMENT: Convert To Array Error! Invalid Xml! at /www/wwwroot/footballInfo/vendor/yansongda/pay/src/Gateways/Wechat/Support.php:306)
[stacktrace]
#0 /www/wwwroot/footballInfo/vendor/yansongda/pay/src/Gateways/Wechat.php(173): Yansongda\\Pay\\Gateways\\Wechat\\Support::fromXml('')
#1 /www/wwwroot/footballInfo/app/Http/Controllers/Api/Wxpay/LoginPaymentController.php(79): Yansongda\\Pay\\Gateways\\Wechat->verify()
#2 /www/wwwroot/footballInfo/vendor/illuminate/container/BoundMethod.php(36): App\\Http\\Controllers\\Api\\Wxpay\\LoginPaymentController->notifyCallback(Object(Laravel\\Lumen\\Http\\Request))
#3 /www/wwwroot/footballInfo/vendor/illuminate/container/Util.php(40): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
#4 /www/wwwroot/footballInfo/vendor/illuminate/container/BoundMethod.php(93): Illuminate\\Container\\Util::unwrapIfClosure(Object(Closure))
#5 /www/wwwroot/footballInfo/vendor/illuminate/container/BoundMethod.php(37): Illuminate\\Container\\BoundMethod::callBoundMethod(Object(Laravel\\Lumen\\Application), Array, Object(Closure))
#6 /www/wwwroot/footballInfo/vendor/illuminate/container/Container.php(651): Illuminate\\Container\\BoundMethod::call(Object(Laravel\\Lumen\\Application), Array, Array, NULL)
#7 /www/wwwroot/footballInfo/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(389): Illuminate\\Container\\Container->call(Array, Array)
#8 /www/wwwroot/footballInfo/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(355): Laravel\\Lumen\\Application->callControllerCallable(Array, Array)
#9 /www/wwwroot/footballInfo/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(329): Laravel\\Lumen\\Application->callLumenController(Object(App\\Http\\Controllers\\Api\\Wxpay\\LoginPaymentController), 'notifyCallback', Array)
#10 /www/wwwroot/footballInfo/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(282): Laravel\\Lumen\\Application->callControllerAction(Array)
#11 /www/wwwroot/footballInfo/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(267): Laravel\\Lumen\\Application->callActionOnArrayBasedRoute(Array)
#12 /www/wwwroot/footballInfo/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(169): Laravel\\Lumen\\Application->handleFoundRoute(Array)
#13 /www/wwwroot/footballInfo/vendor/laravel/lumen-framework/src/Routing/Pipeline.php(48): Laravel\\Lumen\\Application->Laravel\\Lumen\\Concerns\\{closure}(Object(Laravel\\Lumen\\Http\\Request))
#14 /www/wwwroot/footballInfo/app/Http/Middleware/CorsMiddleware.php(31): Laravel\\Lumen\\Routing\\Pipeline->Laravel\\Lumen\\Routing\\{closure}(Object(Laravel\\Lumen\\Http\\Request))
#15 /www/wwwroot/footballInfo/vendor/illuminate/pipeline/Pipeline.php(167): App\\Http\\Middleware\\CorsMiddleware->handle(Object(Laravel\\Lumen\\Http\\Request), Object(Closure))
#16 /www/wwwroot/footballInfo/vendor/laravel/lumen-framework/src/Routing/Pipeline.php(30): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Laravel\\Lumen\\Http\\Request))
#17 /www/wwwroot/footballInfo/vendor/illuminate/pipeline/Pipeline.php(103): Laravel\\Lumen\\Routing\\Pipeline->Laravel\\Lumen\\Routing\\{closure}(Object(Laravel\\Lumen\\Http\\Request))
#18 /www/wwwroot/footballInfo/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(426): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#19 /www/wwwroot/footballInfo/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(175): Laravel\\Lumen\\Application->sendThroughPipeline(Array, Object(Closure))
#20 /www/wwwroot/footballInfo/vendor/laravel/lumen-framework/src/Concerns/RoutesRequests.php(112): Laravel\\Lumen\\Application->dispatch(NULL)
#21 /www/wwwroot/footballInfo/public/index.php(28): Laravel\\Lumen\\Application->run()
#22 {main}
"}
然后改为post请求方式就一切搞定了
$router->post("api/wxpay/notify","LoginPaymentController@notifyCallback");//微信支付回调地址
use Yansongda\Pay\Pay; //引入包
public $wechat = [];
// 下单和唤醒微信支付
public function wechatPay(Request $request)
{
$this->wechat = ['appid' => '', // APP APPID
'app_id' => 'wx3063dafs4fbc3a6f09e', // 公众号 APPID
'miniapp_id' => '', // 小程序 APPID
'mch_id' => '1162163841168',
'key' => '8E1F99E9F2E116AC98F029C71CE8155916E',
'notify_url' => 'https://aaaaaaaa.com/api/wxpay/notify',
'cert_client' => base_path('storage/cert/apiclient_cert.pem'), // optional, 退款,红包等情况时需要用到
'cert_key' => base_path('storage/cert/apiclient_key.pem'),// optional, 退款,红包等情况时需要用到
'log' => [
'file' => storage_path('logs/wechat.log'),
'level' => 'debug', // 建议生产环境等级调整为 info,开发环境为 debug
'type' => 'single', // optional, 可选 daily.
'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
],
'http' => [
'timeout' => 5.0,
'connect_timeout' => 5.0,
],
'mode' => 'normal',];
$user_id = $request->user_id;
$user_level = $request->user_level;
$price = $request->price;
$actual_price = $request->actual_price;
$package_type = $request->package_type;
$openid = $request->openid;
$config = $this->wechat;
$order_num = date("YmdHis").rand(1,100000);
$order = [
'out_trade_no' => $order_num,
'total_fee' => $actual_price*100, // **单位:分**
'body' => 'vip'.$user_level.'购买',
'openid' => $openid,
];
//获取唤醒微信支付参数
$result = Pay::wechat($config)->mp($order)->toarray();
//打印 $result , 是以下参数
//"appId": "wx0632daf4fbc36fasb",
//"timeStamp": "11637571939",
//"nonceStr": "0p2SOtmbt2objoJ5Za",
//"package": "prepay_id=wx22170540055460b70225911e17fe3c0000",
//"signType": "MD5",
//"paySign": "1CE90AFE3EF33E5289AB880D1054C593"
// 生成订单
$insert["user_id"] = $user_id;
$insert["order_num"] = $order_num;
$insert["recharge_type"] = 1;
$insert["status"] = 1;
$insert["add_time"] = date("Y-m-d H:i:s",time());
$insert["goods_type"] = $user_level;
$insert["order_price"] = $price;
$insert["actual_price"] = $actual_price;
$insert["package_type"] = $package_type;
DB::table("order")->insert( $insert );
writeLog('wechatPay', [
'wechatPay' => $result,
'order' => $insert,
],true);
//直接返回给前端,做到这步就可以唤醒微信输入支付密码支付页面了
return $result;
}
// 微信支付回调
public function notifyCallback(Request $request)
{
$config = $this->wechat;
$pay = Pay::wechat($config);
try {
$data = $pay->verify(); // 是的,验签就这么简单!
//以下根据自己业务进行支付校验,更改订单状态什么的,看自己逻辑来
$order = Order::where('order_num', $data->out_trade_no)->get()->toarray();
$order = $order[0];
if (!$order || $order['status'] != 1) {
writeLog('order_info', [
'msg' => "订单状态异常",
],true);
return;
}
if (($order['actual_price']) != $data->total_fee / 100) {
writeLog('order_info', [
'msg' => "金额不匹配",
],true);
return;
}
//进行订单状态变更等支付成功操作
// 更改订单状态
$insert["user_id"] = $user_info["id"];
$insert["status"] = 2;//改为已支付
$insert["update_time"] = date("Y-m-d H:i:s",time());
$ins_id = DB::table("order")->where("order_num",$param["order_num"])->update( $insert );
return $pay->success();
//好了做到这里微信公众号支付就搞定了
} catch (Exception $e) {
writeLog('order_info', [
'error' => $e->getMessage(),
],true);
}
}