准备

需求

需求就是最简单的对接支付宝支付接口

方案心路历程

  1. 简单用http对接一下,不过想了一下觉得第三方提供的SDK总是不用,所以打算尝试一下
  2. 支付宝新版SDK,从文档到git再安装到使用,然后放弃,【文档不详、部分接口不完善】没办法
  3. 支付宝老版SDK,下载引入包装一气呵成

实操

支付宝后台配置

登录支付宝后台—进入后台—点击能力管理—查看已获取能力(手机网站支付)–!没有的话可以点击获取更多能力申请—然后点击管理进入

绑定应用—保存好appid

接着点击密钥管理—进入账户中心—点击开放平台密钥—设置接口加签方式

下载支付宝开发工具

生成密钥保存好应用私钥公钥—复制应用钥在刚刚的加签管理弹窗粘贴—保存设置—然后就会弹出支付宝公钥—复制保存

点击开发工具密钥—粘贴应用公钥—设置本地ip与生产环境ip白名单

到这里支付宝后台的配置就完成了

编码

下载SDK—放入项目中

这里我们使用的是laravel框架为例

直接附上demo code

可以同时参考支付宝接口文档

<?php
namespace App\Services\Support\Ali;
require_once 'aop/AopClient.php'; // 引入SDK类
require_once 'aop/request/AlipayTradeWapPayRequest.php'; // 引入SDK类
use Illuminate\Support\Facades\Log;
class Alipay
{public function __construct(){// 配置SDK$this->baseUrl = config('ali.alipay.baseUrl');$this->appid = config('ali.alipay.appid');$this->privateKey = config('ali.alipay.privateKey');$this->publicKey = config('ali.alipay.publicKey');$this->aliPublicKey = config('ali.alipay.aliPublicKey');$this->sign_type = "RSA2";$this->charset = "utf-8";}public function wapPay($options){$aop = new \AopClient();$aop->gatewayUrl = $this->baseUrl . 'gateway.do';$aop->appId = $this->appid;$aop->rsaPrivateKey = $this->privateKey;$aop->alipayrsaPublicKey = $this->aliPublicKey;$aop->apiVersion = '1.0';$aop->signType = 'RSA2';$aop->postCharset = 'utf-8';$aop->format = 'json';$request = new \AlipayTradeWapPayRequest();// 配置支付信息$request->setReturnUrl($options['returnUrl']);$request->setNotifyUrl($options['notifyUrl']);$content = ["subject" => $options['subject'],"out_trade_no" => $options['outTradeNo'],"total_amount" => $options['totalAmount'],"quit_url" => $options['quitUrl'],"product_code" => "QUICK_WAP_PAY",];$bizContent = json_encode($content);$request->setBizContent($bizContent);$result = $aop->pageExecute($request);// 创建支付订单,返回支付页面的Form// Log::info("Alipay->wapPay():result: $result");return $result;}
}

服务入口

<?php
namespace App\Services;
use App\Services\Support\Ali\Alipay;
class Ali
{public function __construct(){}public function alipay(){return new Alipay();}
}

路由入口

<?php
namespace App\Http\Controllers;
use App\Services\Ali;
use App\Utils\Common\DataHandle;
class TestController extends Controller
{public function test(){$systemSlug = 'test';return response()->json((new Ali())->alipay()->wapPay(["subject" => '支付测试',"totalAmount" => 0.01,'outTradeNo' => sprintf("%s_%s_%s", $systemSlug, time(), DataHandle::strRandom(17, 'key')), // 自定义'timestamp' => date('Y-m-d H:i:s'),'quitUrl' => config('ali.alipay.quitUrl'),'returnUrl' => config('ali.alipay.returnUrl'),'notifyUrl' => config('ali.alipay.notifyUrl') . 100,]));}
}

SDK返回的form内容

<form id='alipaysubmit' name='alipaysubmit' action='https://openapi.alipay.com/gateway.do?charset=utf-8' method='POST'><input type='hidden' name='biz_content' value='{\"subject\":\"test\",\"out_trade_no\":\"test_1623329685_lpfbl1dan16dd5xw2\",\"total_amount\":0.01,\"quit_url\":\"xxx\",\"product_code\":\"QUICK_WAP_PAY\"}'/><input type='hidden' name='app_id' value='xxx'/><input type='hidden' name='version' value='1.0'/><input type='hidden' name='format' value='json'/><input type='hidden' name='sign_type' value='RSA2'/><input type='hidden' name='method' value='alipay.trade.wap.pay'/><input type='hidden' name='timestamp' value='2021-06-10 20:54:45'/><input type='hidden' name='alipay_sdk' value='alipay-sdk-PHP-4.11.14.ALL'/><input type='hidden' name='notify_url' value='xxx'/><input type='hidden' name='return_url' value='xxx'/><input type='hidden' name='charset' value='utf-8'/><input type='hidden' name='sign' value='xxx'/><input type='submit' value='ok' style='display:none;''></form><script>document.forms['alipaysubmit'].submit();</script>

前端处理form,我这里使用的是uniapp,这个东西也踩了我很多坑

this.$http.post({path: "test",dontShowToast: true,errData: true,data: data,
}).then((res) => {if (this.alipay) {//将接口返回的Form表单显示到页面document.querySelector("body").innerHTML = res.data;//调用submit 方法document.forms[0].submit();}console.log(res.message);this.submitSuccess();
})

效果

异步处理结果

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Api\Controller;
use App\Payorder;
use App\Services\Ali;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class NotifyController extends Controller
{public function payCall($payType){try {switch ($payType) {case 100:// 支付宝手机网站支付$data = $_POST;// 异步回调验签if (!(new Ali())->alipay()->signCheck($data)) {Log::error("fails for notify, 验签失败 data: " . json_encode($data));return $this->rsp(403, []);}$orderId = $data['out_trade_no'];$statusMapState = ['WAIT_BUYER_PAY' => 0, // 交易创建,等待买家付款。'TRADE_CLOSED' => -1, // 在指定时间段内未支付时关闭的交易或在交易完成全额退款成功时关闭的交易。'TRADE_SUCCESS' => 1, // 商户签约的产品支持退款功能的前提下,买家付款成功。'TRADE_FINISHED' => 2, // 商户签约的产品不支持退款功能的前提下,买家付款成功;或者,商户签约的产品支持退款功   能的前提下,交易已经成功并且已经超过可退款期限。];$state = $statusMapState[$data['trade_status']];break;default:return $this->rsp(403, []);}} catch (\Exception $e) {Log::error("fails for notify, $e");return $this->rsp(403, []);}DB::beginTransaction();// 支付完成操作$payorder = Payorder::where(['order_id' => $orderId, 'state' => 0])->first();if (!$payorder) {DB::rollBack();return $this->rsp(400, [], '参数错误');}$payorder->notifyData = $data;$payorder->state = $state;$payorder->save();DB::commit();return $this->rsp(0, []);}
}

这个demo中只是简单的记录支付结果我配置的异步回调url是https://xxx/api/notify/payCall/{paytype}

踩坑

laravel与aop冲突

laravel中引入aop会导致框架自定义函数与SDK冲突,这里我们需要手动修改SDK源码

将原本的encryptdecrypt函数名修改成自定义的名字,我这里修改为alipayEncrptalipayDecrypt

然后把使用到这两个函数的源码也一并修改

我这里是已经修改好之后的

支付完成同步回调失效

在使用SDK中的alipay.trade.wap.pay接口时遇到了同步回调失效问题

跟踪问题

在上面的代码中是已经设置了同步回调和异步回调配置的,这里忍不住吐槽一下支付宝文档,找不到在哪里可以配置这两个参数

这是支付宝的请求实例代码

$aop = new AopClient ();
$aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
$aop->appId = 'your app_id';
$aop->rsaPrivateKey = '请填写开发者私钥去头去尾去回车,一行字符串';
$aop->alipayrsaPublicKey='请填写支付宝公钥,一行字符串';
$aop->apiVersion = '1.0';
$aop->signType = 'RSA2';
$aop->postCharset='GBK';
$aop->format='json';
$request = new AlipayTradeWapPayRequest ();
$request->setBizContent("{" .
"\"body\":\"Iphone6 16G\"," .
"\"subject\":\"大乐透\"," .
"\"out_trade_no\":\"70501111111S001111119\"," .
"\"timeout_express\":\"90m\"," .
"\"time_expire\":\"2016-12-31 10:05\"," .
"\"total_amount\":9.00," .
"\"auth_token\":\"appopenBb64d181d0146481ab6a762c00714cC27\"," .
"\"goods_type\":\"0\"," .
"\"quit_url\":\"http://www.taobao.com/product/113714.html\"," .
"\"passback_params\":\"merchantBizType%3d3C%26merchantBizNo%3d2016010101111\"," .
"\"product_code\":\"QUICK_WAP_PAY\"," .
"\"promo_params\":\"{\\\"storeIdType\\\":\\\"1\\\"}\"," .
"\"extend_params\":{" .
"\"sys_service_provider_id\":\"2088511833207846\"," .
"\"hb_fq_num\":\"3\"," .
"\"hb_fq_seller_percent\":\"100\"," .
"\"industry_reflux_info\":\"{\\\\\\\"scene_code\\\\\\\":\\\\\\\"metro_tradeorder\\\\\\\",\\\\\\\"channel\\\\\\\":\\\\\\\"xxxx\\\\\\\",\\\\\\\"scene_data\\\\\\\":{\\\\\\\"asset_name\\\\\\\":\\\\\\\"ALIPAY\\\\\\\"}}\"," .
"\"card_type\":\"S0JP0000\"," .
"\"specified_seller_name\":\"XXX的跨境小铺\"" .
"    }," .
"\"merchant_order_no\":\"20161008001\"," .
"\"enable_pay_channels\":\"pcredit,moneyFund,debitCardExpress\"," .
"\"disable_pay_channels\":\"pcredit,moneyFund,debitCardExpress\"," .
"\"store_id\":\"NJ_001\"," .
"      \"goods_detail\":[{" .
"        \"goods_id\":\"apple-01\"," .
"\"alipay_goods_id\":\"20010001\"," .
"\"goods_name\":\"ipad\"," .
"\"quantity\":1," .
"\"price\":2000," .
"\"goods_category\":\"34543238\"," .
"\"categories_tree\":\"124868003|126232002|126252004\"," .
"\"body\":\"特价手机\"," .
"\"show_url\":\"http://www.alipay.com/xxx.jpg\"" .
"        }]," .
"\"specified_channel\":\"pcredit\"," .
"\"business_params\":\"{\\\"data\\\":\\\"123\\\"}\"," .
"\"ext_user_info\":{" .
"\"name\":\"李明\"," .
"\"mobile\":\"16587658765\"," .
"\"cert_type\":\"IDENTITY_CARD\"," .
"\"cert_no\":\"362334768769238881\"," .
"\"min_age\":\"18\"," .
"\"fix_buyer\":\"F\"," .
"\"need_check_info\":\"F\"" .
"    }" .
"  }");
$result = $aop->pageExecute ( $request); $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
$resultCode = $result->$responseNode->code;
if(!empty($resultCode)&&$resultCode == 10000){echo "成功";
} else {echo "失败";
}

不过通过查看AlipayTradeWapPayRequest我找到了这两个函数

但是这反而让我迷失自我了,同步回调url已经设置好了,那么为什么还会失效呢??

百度了一圈,并没有找到问题

emmm…

接着,终于发现问题关键点,我习惯保留第三方对接的上下文,回来查看SDK给我返回的form

我发现SDK给我返回的formnotify_url但是并没有return_url`这个input,上图是修复问题后的返回结果

于是我又回去看SDK源码

这里附上完整的AopClient类中的pageExecute函数

<?phprequire_once 'AopEncrypt.php';
require_once 'EncryptParseItem.php';
require_once 'EncryptResponseData.php';
require_once 'SignData.php';class AopClient
{...public function pageExecute($request, $httpmethod = "POST", $appAuthToken = null){$this->setupCharsets($request);if (strcasecmp($this->fileCharset, $this->postCharset)) {// writeLog("本地文件字符集编码与表单提交编码不一致,请务必设置成一样,属性名分别为postCharset!");throw new Exception("文件编码:[" . $this->fileCharset . "] 与表单提交编码:[" . $this->postCharset . "]两者不一致!");}$iv = null;if (!$this->checkEmpty($request->getApiVersion())) {$iv = $request->getApiVersion();} else {$iv = $this->apiVersion;}//组装系统参数$sysParams["app_id"] = $this->appId;$sysParams["version"] = $iv;$sysParams["format"] = $this->format;$sysParams["sign_type"] = $this->signType;$sysParams["method"] = $request->getApiMethodName();$sysParams["timestamp"] = date("Y-m-d H:i:s");$sysParams["alipay_sdk"] = $this->alipaySdkVersion;if (!$this->checkEmpty($request->getTerminalType())) {$sysParams["terminal_type"] = $request->getTerminalType();}if (!$this->checkEmpty($request->getTerminalInfo())) {$sysParams["terminal_info"] = $request->getTerminalInfo();}if (!$this->checkEmpty($request->getProdCode())) {$sysParams["prod_code"] = $request->getProdCode();}if (!$this->checkEmpty($request->getNotifyUrl())) {$sysParams["notify_url"] = $request->getNotifyUrl();}$sysParams["charset"] = $this->postCharset;if (!$this->checkEmpty($appAuthToken)) {$sysParams["app_auth_token"] = $appAuthToken;}//获取业务参数$apiParams = $request->getApiParas();if (method_exists($request, "getNeedEncrypt") && $request->getNeedEncrypt()) {$sysParams["encrypt_type"] = $this->encryptType;if ($this->checkEmpty($apiParams['biz_content'])) {throw new Exception(" api request Fail! The reason : encrypt request is not supperted!");}if ($this->checkEmpty($this->encryptKey) || $this->checkEmpty($this->encryptType)) {throw new Exception(" encryptType and encryptKey must not null! ");}if ("AES" != $this->encryptType) {throw new Exception("加密类型只支持AES");}// 执行加密$enCryptContent = alipayEncrypt($apiParams['biz_content'], $this->encryptKey);$apiParams['biz_content'] = $enCryptContent;}//print_r($apiParams);$totalParams = array_merge($apiParams, $sysParams);//待签名字符串$preSignStr = $this->getSignContent($totalParams);//签名$totalParams["sign"] = $this->generateSign($totalParams, $this->signType);if ("GET" == strtoupper($httpmethod)) {//value做urlencode$preString = $this->getSignContentUrlencode($totalParams);//拼接GET请求串$requestUrl = $this->gatewayUrl . "?" . $preString;return $requestUrl;} else {//拼接表单字符串return $this->buildRequestForm($totalParams);}}...
}

看完,同志们发现什么了吗???

有设置notify_url参数,并没有设置return_url的代码,what??

恕我愚昧,我不知道这算不算bug,不过在我的demo里的确是同步回调失败

最后,修改为以上代码,解决问题

支付宝手机网站支付实战踩坑相关推荐

  1. 微信H5支付实战踩坑

    准备 需求 需求就是最简单的对接微信H5支付接口 方案心路历程 之前直接用http对接过,不过这次想用官方提供的SDK 一方面SDK提供的接口比较完整,二方面感觉应该使用别人辛苦写下来的封装 百度了一 ...

  2. php手机网站支付宝_PHP实现支付宝手机网站支付功能

    PHP实现支付宝手机网站支付功能的方法:首先开通支付宝商家中心里面的手机网站支付:然后进入开发者中心,获取到APPID:接着去文档中心下载"DEMO":最后将"demo& ...

  3. 支付宝手机网站支付补全信息提示 系统综合评估签约条件不满足解决

    申请支付宝 手机网站支付 成功后需补全经营信息,但是补全提交时提示  "系统综合评估签约条件不满足解决",需要检查下自己的支付宝账号是否满足以下申请条件: 1.申请前必须拥有经过实 ...

  4. 支付--支付宝手机网站支付(WAP)

    介绍: 这是放在微信供公众号内的一个项目,支付模块设计到微信公众号支付和支付宝手机网站支付,这次把支付宝手机网站支付整理下来. 文档: 支付宝手机网站支付的开发文档: https://docs.ope ...

  5. 4 支付宝手机网站支付demo讲解

    目录 1 引言 2 业务流程 3 用户下单 4 商户系统处理订单信息 5 支付宝向用户展示支付信息 6 用户付款 7 同步通知与异步通知 1 引言 前面三小节我们已经学过如何使用支付宝手机网站支付的功 ...

  6. 对接支付宝手机网站支付接口,alin10071

    最近项目要增加支付宝扫二维码实现h5支付的功能,我们采用了调用支付宝手机网站支付接口:alipay.trade.wap.pay 但是每次调起返回都是 无可用支付方式 测了一天才发现是因为我的支付宝余额 ...

  7. Magento支付宝手机网站支付插件V6.0旗舰版发布,支持在微信中使用支付宝支付,订单重新支付功能!...

    2019独角兽企业重金招聘Python工程师标准>>> 功能 严格按照支付宝接口文档编写代码. 支付宝异步通知机制,确保订单状态及时更新,无丢失遗漏. 订单完美对接:支付后即使关掉支 ...

  8. 支付宝手机网站支付签约强开WAP支付,提示“系统综合评估签约条件不满足”或不满足国家法律法规或支付宝用户服务协议等的解决方案!支付宝H5支付开通方法详解

    一.如何开通支付宝手机网站支付 正常来说,按照官方的指引要求填写相关资料,即可开通支付宝手机网站支付.但是,更多的时候我们的申请都会碰到一些阻力,常见的阻力就是"系统综合评估签约条件不满足, ...

  9. 【支付宝支付】Java实现支付宝手机网站支付流程

    前言 微信登录网页授权与APP授权 微信JSAPI支付 微信APP支付 微信APP和JSAPI退款 支付宝手机网站支付 支付宝APP支付 支付宝退款 以上我都放到个人公众号,搜一搜:JAVA大贼船,文 ...

最新文章

  1. html单击数字显示图片,记SpannableString金融数字显示与Html.from显示图片
  2. php和python区别-PHP与Python语言有哪些区别之处?选择哪一个好?
  3. [css] 举例说明微信端兼容问题有哪些?
  4. php程序设计案例教程 程序题,PHP程序设计案例教程
  5. 天人短文网站系统v5.53源码
  6. Macbook Pro 光驱坏 安装windows
  7. igs无法分配驱动器映射表_左神算法基础:哈希函数和哈希表
  8. Activiti Explorer messages 国际化文件
  9. android usb 9008,【2018.1.4更新】X极Qualcomm HS-USB QDLoader 9008救砖的4种方法
  10. java 逃逸_Java 逃逸分析
  11. 别人笑我太疯癫 唐伯虎诗词集
  12. Linux杀毒软件之ClamAV使用详解
  13. 微信小说域名被封-366tool在线解答微信屏蔽小说网页停止访问的解决方案
  14. Qt学习:无边框界面的实现总结
  15. 借助Excel批量重命名图片、文档,以及处理文件名中的空格问题(适合新手小白)
  16. 不可不知的10款3dMax展UV插件
  17. 随笔之与潇哥交谈1h12min内容//2021-1-28【最后一个寒假作业】
  18. vue3 +Ts后导包出现红色波浪线【vscode】
  19. Linux安装配置ssh 基于unbantu22.04.1 LTS版本
  20. fscanf()php,fscanf()函数fscanf

热门文章

  1. 前端架构设计第六课工程化构建、编译、运行
  2. hadoop2.7.4在windows系统IDEA远程测试
  3. L3-python语言中的几种特征操作
  4. 五笔打字:速成手册---半小时学会五笔打字
  5. linux添加网卡设备,Linux添加网卡教程
  6. 计算机毕业设计ssm+vue基本微信小程序的快递柜管理系统
  7. 万字长文读懂SaaS的中国版图、问题及趋势
  8. PythonStock(16):使用bokeh 展示,股票中的16个常用指标
  9. arcgis desktop和arcgis engin连接postgresql数据库连接需要的类库
  10. Scrapy爬取斗破苍穹漫画