内网穿透-测试支付

测试支付

现在我们需要测试一下支付成功之后的逻辑。

我们在上一个课程开发支付宝和微信支付的过程中,由于开发环境没有外网 IP,支付宝和微信支付的回调无法直接访问到开发环境的接口,每次支付都需要使用 Requestbin 捕获支付成功回调,然后再在终端里使用 curl 手动请求开发环境的回调接口,十分麻烦。

为了让我们更专注于业务功能的开发,下面我们来学习一下内网穿透神器 Ngrok 的使用。

Ngrok 是一个反向代理软件,启动后会在公共服务器和本地客户端之间建立一个通道,并由公共服务器分配一个唯一的域名给这个通道。在 Homestead 中运行 Ngrok 之后,通过公共服务器分配的域名就可以在公网访问到 Homestead 中的站点,从而让支付宝和微信支付的服务器直接将回调数据发送到对应的回调接口。

1. 注册 Ngrok 账号

Ngrok 官方提供了免费的公共服务器,但需要注册才能使用,访问这个链接注册:

file

注册表单包含了一个谷歌验证码,所以需要翻墙才能正常注册。如果没有翻墙梯子,也可以点击该页面下方的 Github 注册按钮,可以直接注册成功。

2. Homestead 配置 Ngrok 客户端

Homestead 中内置了 Ngrok 客户端,但需要配置 Token 之后才能正常使用。

Ngrok 注册完成之后会进入这个页面:

file

复制这个框里的命令,但不需要开头的 ./,然后在 Homestead 中粘贴执行:

$ ngrok authtoken {你的 Token}

file

3. 启动 Ngrok 客户端

接下来我们需要在 Homestead 中启动 Ngrok 客户端以建立本地与公共服务器的链接:

$ ngrok http -host-header=shop.test -region us 80

http 代表我们要映射的是 HTTP 协议;-host-header= 代表本地站点的域名,如果你用的不是 shop.test请更换成对应的域名;-region us 代表我们要使用的是美国的公共节点;80 代表映射到 Homestead 的 80 端口。

运行之后应该可以看到如下界面:

file

Forwarding 代表 Ngrok 分配给你的域名,对于免费账号来说,每次启动 Ngrok ,都会重新分配一个随机的域名,无法固定。

Web Interface 是 Ngrok 内置的一个管理面板,它可以展示所有通过 Ngrok 进来的请求信息以及返回的数据,现在我们访问一下 http://192.168.20.10:4040 看看:

file

可以看到目前还没有任何请求,现在我们复制一下 Ngrok 分配给我们的随机域名,我这次分配到的是 http://80c8fa45.ap.ngrok.io,在浏览器中打开:

file

国际带宽不稳定的时候有可能出现连接超时,这个时候可以试试把启动 Ngrok 命令中的 us 改成 au 澳大利亚或者 eu 欧洲。

可以看到这正是我本地的 Laravel Shop 站点,现在再看看 Ngrok 的管理面板:

file

可以看到请求的包以及返回的数据。

4. 在 Laravel Shop 中使用

接下来我们来调整一下我们的代码。

首先我们把 Ngrok 分配的随机域名放到 .env 文件中:

.env

.
.
.
NGROK_URL=http://{分配给你的域名}.ngrok.io

然后在配置文件中读取:

config/app.php

.
.
.
    'ngrok_url' => env('NGROK_URL'),
];

为了方便调用,我们在 helpers.php 中新建一个函数:

bootstrap/helpers.php

.
.
.
function ngrok_url($routeName, $parameters = [])
{
    // 开发环境,并且配置了 NGROK_URL
    if(app()->environment('local') && $url = config('app.ngrok_url')) {
        // route() 函数第三个参数代表是否绝对路径
        return $url.route($routeName, $parameters, false);
    }

    return route($routeName, $parameters);
}

现在我们在 tinker 中测试一下这个函数:

>>> ngrok_url('products.index')

file

可以看到能正常返回 Ngrok 地址。

现在我们调整一下几处支付的回调地址:

app/Providers/AppServiceProvider.php

.
.
.
    public function register()
    {
        $this->app->singleton('alipay', function () {
            $config = config('pay.alipay');
            $config['notify_url'] = ngrok_url('payment.alipay.notify');
            .
            .
            .
        });

        $this->app->singleton('wechat_pay', function () {
            $config = config('pay.wechat');
            $config['notify_url'] = ngrok_url('payment.wechat.notify');
            .
            .
            .
        });
    }
.
.
.

然后是管理后台微信支付退款回调的代码:

app/Admin/Controllers/OrdersController.php

.
.
.
    public function _refundOrder(Order $order)
    {
        switch ($order->payment_method) {
            case 'wechat':
                $refundNo = Order::getAvailableRefundNo();
                app('wechat_pay')->refund([
                    .
                    .
                    .
                    'notify_url' => ngrok_url('payment.wechat.refund_notify'),
                ]);
                .
                .
                .

在本地开发环境时,支付回调就会被发往 Ngrok 的域名然后映射到 Homestead 中的站点;而在正式环境时 ngrok_url() 函数的作用与 route() 函数一致,不会有其他影响。

5. 测试众筹订单支付

现在我们来测试一下众筹订单的支付,请确保 Ngrok 处于启动状态。

首先到众筹商品详情页创建一个新的众筹订单:

这里仍然使用我们本地开发域名即可,无需使用 Ngrok 的 URL。

file

下单成功后跳转到订单详情页,点击『支付宝支付』:

file

支付成功之后,看看启动 Ngrok 的终端:

file

可以看到有支付回调进来,现在再看看订单详情页:

file

可以看到状态已经变成『已支付』。

现在我们在终端启动一个队列处理器:

$ php artisan queue:work

file

可以看到 UpdateCrowdfundingProductProgress 监听器已经执行了。

现在再访问一下众筹商品详情页:

file

可以看到数据也更新了。

Git 代码版本控制

现在让我们将这些变更加入到版本控制中:

$ git add -A
$ git commit -m "开发环境加入 Ngrok"
tags: PHP,laravel