PCDotFan

To be an life & code artisan

初试 Laravel 支付宝支付开发

Laravel 0 评

过来水一篇,这次使用的是 Yangsongda/Pay,不用写各种拼字符串的代码真是太幸福了。

想跑通整个支付流程,提供订单号、AK、SK 这类资料也已经是老生常谈了。不过最让人感到一头雾水的应该是 notify_urlreturn_url 两个概念。

官方版

notify_url:对于 PC 网站支付的交易,在用户支付完成之后,支付宝会根据 API 中商户传入的 notify_url,通过 POST 请求的形式将支付结果作为参数通知到商户系统。 return_url:支付宝处理完成后,浏览器当前页面自动跳转回商户网站中指定页面的路径,同时返回订单信息。

什么鬼……最后折腾了半小时才弄懂支付宝文档想说什么。

人话版

Return URL

功能:买家支付成功后跳转到自己网站的「支付成功」页面。

Notify URL

功能:减少掉单几率(听说是 0.0001%)、帮助网站主及时处理交易成功的订单(我乱说的) 流程:

  1. 用户根据步骤依次下单、支付且支付成功后,支付宝会将订单状态更改为:「等待发货」(trade_status=WAIT_SELLER_SEND_GOODS)
  2. 同时支付宝将不断以 POST 的形式向所提供的 notify_url 发送数据,包括给客户生成的交易订单号 out_trade_no 还有支付金额 total_amount 等等。这时就应借此机会来校验订单金额是否正确、交易订单号是否与网站上的相符等等,还有就是做发货之类的任务分发
  3. 当以上操作全部结束时,应在 notify_url 返回一个 success 以告诉支付宝你已收到订单通知
  4. 为了避免掉单,支付宝会在用户付款成功时就不断向 notify_url 发起通知,直至网页返回 success。当然,如果 48 小时后通知仍不成功,则视为交易失败。

诶?要是第二步的时候发现订单金额不对怎么办?面对这种情况,你也可以选择给支付宝返回 fail(我没试过)。但一般不这么做——通常可以先令程序记录下有问题的订单,给支付宝返回 success 后再人工处理。

DEMO

定义两个 URL 的路由:

Route::get('/alipay/notify', 'OrdersController@notify')->name('alipay.notify');
Route::get('/alipay/return', 'OrdersController@paymentSuccess')->name('alipay.return');
    /**
     * 支付宝网站支付实现
     *
     * @param int $id
     *
     * @return \Illuminate\Http\Response
     */
    public function pay(Art $art, Order $order) {
        if ($order->status == 'unpaid') {
            // 构建支付信息
            $billing_config = [
                'out_trade_no' => $order->order_id,
                'total_amount' => 1,
                'subject' => "订单:$order_id",
                'body' => "这是 XXX 在网站的 XXX 购买订单,生成于 $order_create_at",
                'timeout_express' => '1c', // 表示订单将在 1 天后自动关闭
                'goods_type' => '0'
            ];
            // 发起支付请求
            return \Pay::driver('alipay')->gateway('web')->pay($billing_config);
        }
        
        abort(404);
    }

    public function paymentSuccess(Order $order) {
        if ($order->status == 'success') {
            return view('orders.success', compact('order'));
        }
        abort(404);
    }

    public function notify(Request $request)
    {
        if (\Pay::driver('alipay')->gateway('web')->verify($request->all())) {
            /*
                接收支付宝通知信息,开始处理                
             */
             // 校验订单号
            $order = Order::findorFail($request->out_trade_no);
            if ($order->status == 'unpaid') {
                // 校验金额
                if ($request->total_amount == $order->price) {
                    $order->status = 'success';
                    // 接下来就是支付成功后的逻辑
                    // 发货、加积分 blablabla
                }
            } else {
                // 手动记录错误订单
                $order->description = '支付状态异常,原因可能是订单金额不符或者订单状态不满足交易成功要求,请直接联系网站管理员处理。';
                $order->status = 'warning';
                $order->save();
            }
        }
        // 即使发现异常也返回 success
        echo "success";
    }