股票场内基金交易,没时间盯盘?
折腾了半个多月的支付宝接入终于跑通了。
SDK选择
接入支付宝首先需要引入支付宝的SDK,可供选择的有官方SDK和第三方集成的SDK。经过仔细比较筛选之后最终还是选择了第三方的SDK,主要原因如下:
- 支付宝官方SDK不支持composer引入。需要在项目中引入上百个PHP文件,处理起来比较麻烦
- 第三方SDK对一些校验方法进行了很好的封装,使用方便。
SDK安装
- 打开
composer.json
文件,加入"lokielse/omnipay-alipay": "^2.0",
依赖 - 在项目文件夹下输入命令
composer update -vvv
此时这个lib就安装完成了。
支付宝设置
打开支付宝开放平台网址,登录.
登录进去之后点击创建一个新的应用。具体的设置请参照创建应用
以及生成RSA密钥 这两篇文章。
请一定按照官方文档一步一步认真操作。其中,应用的基础环境里的应用网关和授权回调地址可以暂时先不用填。
服务器端代码编写
本次开发主要功能是手机App支付接口官方文档,因此有些功能需要安卓客户端或者iOS客户端联动调试。如果是调试手机网站支付功能,则可以使用Laravel来完成全部的开发,不过具体的思路都是一样的。
路由
1 2 3 4 5 6 7 8 9 10 11 |
//routes.php $api->version('v1.0', ['namespace' => 'App\Http\V1_0\Controllers'], function($api) { $api->post('alipay/notify', 'AliPayController@notify'); // 支付宝异步通知 $api->post('alipay/return', 'AliPayController@AlipayReturn'); //支付宝同步通知 $api->group(['middleware' => 'jwt.auth', 'providers' => 'jwt'],function($api) { $api->post('alipay', 'AliPayController@pay'); // 支付宝支付 }); }); |
项目使用了dingo/api+jwt开发,alipay
路由用于生成支付订单。alipay/return
用于返回同步通知的结果,alipay/notify
用于返回异步通知的结果。
控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
<?php namespace App\Http\V1_0\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Omnipay\Omnipay; class AliPayController extends ApiController { public function __construct() { $this->gateway = Omnipay::create('Alipay_AopApp'); $this->gateway->setAppId(env('ALIPAY_APPID')); $this->gateway->setPrivateKey(env('ALIPAY_PRIVATE_KEY')); $this->gateway->setAlipayPublicKey(env('ALIPAY_PUBLIC_KEY')); $this->gateway->setNotifyUrl(env('ALIPAY_NOTIFY_URL')); $this->gateway->setSignType('RSA2'); $this->gateway->setEnvironment('sandbox'); //正式环境需要设置为production } public function pay(Request $request) { $result = $this->gateway->purchase(); $result->setBizContent([ 'subject' => $order->subject_title, 'out_trade_no' => $order->channel_order_num, 'total_amount' => $order->amount / 100.0, 'body' => $order->subject_intro, 'product_code' => 'QUICK_MSECURITY_PAY', 'goods_type' => 0, 'timeout_express' => $order->channel_expired_time, ]); $response = $result->send(); $orderString = $response->getOrderString(); return ["order" => $orderString]; } public function AlipayReturn(Request $request) { $params = $request->all(); $result = $this->gateway->completePurchase(); $result->setParams([ 'memo' => $params['memo'], 'result' => $params['result'], 'resultStatus' => $params['resultStatus'], ]); try { $response = $result->send(); if ($response->isPaid()) { return $this->response->array(['message' => trans('success.alipay.return')]); } else { return $this->response->array(['message' => trans('failure.alipay.fail')]); } } catch (Exception $e) { return $this->response->array(['message' => trans('failure.alipay.fail')]); } } public function notify(Request $request) { $result = $this->gateway->completePurchase(); $result->setParams($request->all()); try { $response = $result->send(); if ($response->isPaid()) { if (!$this->paymentInterface->checkOrder($request->all())) { Log::info('异步通知支付成功'); // for test return 'success'; } } else { return 'fail'; } } catch (Exception $e) { return 'fail'; } } } |
需要说明的是我在文章的代码里省略了自己服务器有关数据库的操作,在自己写项目的时候进行相应的处理。首先我在控制器的构造函数中实例化了Omnipay
对象,其中create里面有6种方法,Alipay_AopApp
是手机app支付接口的方法,其他方法可以到GitHub上自己查看对应的内容。
另外,我把支付宝需要用到的关键信息,如私钥、公钥、APPID等等都写到了Lumen的env文件里,这样可以防止关键信息泄露。另外,如果使用沙盒环境测试的话需要配置沙盒环境的APPID、私钥、公钥等等,和你在开始创建的应用的是不一样的。构造函数的setNotifyUrl
是设置你的异步回调网址的,还记得我们的路由文件么,就是那里的那个alipay/notify
地址。比如,我在代码编写完之后将整个项目上传到服务器,域名是http://www.test.com
,那么此时,这个异步回调的setNotifyUrl
网址就应该是http://www.test.com/alipay/notify
。并且,你在支付宝应用的基础信息设置里也要将授权回调地址设置为这个。注意,异步通知接口是没办法在本地环境进行测试的,必须上传到能够访问外网的服务器来进行调试。同时,这里的PUBLIC KEY是支付宝公钥,不是应用公钥。一定要注意
接下来就比较简单了,按照这个GitHub的介绍的方法,进行处理就可以。不过,涉及到数据库的操作(比如,创建订单时,你在数据库里插入了一条数据库,数据库状态为待支付,支付成功后想更改为已支付状态)一定要在异步通知的方法里进行,不推荐在同步通知那里进行,同步通知只应该返回支付消息供客户端调用。
异步通知是在进行支付之后阿里的服务器会自动向你设置好的异步通知路由发送POST消息,并且将返回的结果传送回阿里服务器,如果异步通知成功,只能返回success
这7个字母组成的字符串,除此之外,其他任何的返回都会被忽略。同时,如果是使用Laravel开发的话,你可能还会需要将这个异步通知路由排除csrfToken验证,理由是由于该回调请求来自第三方API,无法通过CSRF验证,所以需要在CSRF验证中排除该URL,否则会抛出TokenMismatchException异常。排除方法请看这里。
测试
代码写完之后就是测试了,其中支付和同步通知是可以POSTMAN来进行测试的。如下图,是本地测试的支付API,如果返回类似的字符串,你应该就基本上成功发起支付了。
由于是第一次对接支付宝API,导致我在调试异步通知的时候卡了我很长时间。这个坑就是。。。你是没法用POSTMAN来调试异步通知的,因为异步通知是支付宝直接发给这个路由,并且返回数据给阿里服务器。在我最开始写完代码后用POSTMAN调试,一直出现错误,百思不解。后来灵光一现,才发现是没法使用POSTMAN来进行调试的。想要调试异步通知只能通过Lumen的Log来记录相关的信息具体参考上面的代码。并且如果你的异步通知出现了错误,则可以在每一步执行代码里分别记录Log,进行排查原因。
总结
有了这次经历之后,让我掌握了支付宝的基本支付功能,相信以后开发支付宝相关的其他功能或者微信支付功能都会很快的处理好。当然,我上面的代码还有能够继续优化的空间,比如同步和异步方法代码结构相似,是可以写成一个通用的方法来进行调用的。不过这些问题已经是比较简单的了。等对接微信支付的时候可以考虑一下再次优化。请期待我的微信支付文章吧(然而,并没有公司账号,貌似无法申请微信支付)。
想获得去掉 5 元限制的证券账户吗?

如果您想去掉最低交易佣金 5 元限制,使用微信扫描左边小程序二维码,访问微信小程序「优财助手」,点击底部菜单「福利」,阅读文章「通过优财开证券账户无最低交易佣金 5 元限制」,按照文章步骤操作即可获得免 5 元证券账户,股票基金交易手续费率万 2.5。
请注意,一定要按照文章描述严格操作,如错误开户是无法获得免 5 元证券账户的。