背景:
公司需要增加一项支付宝PC端的收款功能
解决:
使用的支付宝官方文档中的电脑网站支付->统一收单下单并支付,当然,我们的支付宝账号需要开通该产品。官方API连接:https://opendocs.alipay.com/open/028r8t?pathHash=8e24911d&ref=api&scene=22。调用流程如下:
一、其中1.1对支付宝发起支付请求时,返回的是一个HTML文本,我们后端拿到文本后返回给前端,前端将表单进行提交,将会新生成一个支付宝二维码收银台。
二、其中6,是支付完成后要跳转的界面,会有个5S的跳转缓冲时间,期间支付宝会发起7:异步通知,我们同步通知和异步通知都要写,来确保支付通知不会丢失。
● 用户确认支付后,支付宝通过 get 请求 returnUrl(商户入参传入),返回同步返回参数。
● 交易成功后,支付宝通过 post 请求 notifyUrl(商户入参传入),返回异步通知参数。
● 接收到支付成功通知,必须进行验签,这个官方已经封装好了
Map<String, String> paramsMap = ... //将异步通知中收到的所有参数都存放到map中
boolean signVerified = AlipaySignature.rsaCheckV1(paramsMap, ALIPAY_PUBLIC_KEY, CHARSET, SIGN_TYPE) //调用SDK验证签名
if(signVerified){
// TODO 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure
}else{
// TODO 验签失败则记录异常日志,并在response中返回failure.
}
三、同步或者异步通知验签成功后,还必须再次校验数据的正确性
- 商家需要验证该通知数据中的 out_trade_no 是否为商家系统中创建的订单号。
- 判断 total_amount 是否确实为该订单的实际金额(即商家订单创建时的金额)。
- 校验通知中的 seller_id(或者 seller_email) 是否为 out_trade_no 这笔单据的对应的操作方(有的时候,一个商家可能有多个 seller_id/seller_email)。
- 验证 app_id 是否为该商家本身。
上述 1、2、3、4 有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。
只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。
四、异步通知返回应遵守返回要求
成功应该返回success,如果支付宝收到的应答不是 success,支付宝会认为通知失败,会通过一定的策略定期重新发起通知。通知的间隔频率为:4m、10m、10m、1h、2h、6h、15h。不遵守规范,如果用户支付多次,这样会造成“ABA”问题,导致订单在某段时间状态不正常。
五、需要注意并发问题
支付成功后的同步通知、异步通知、以及异步通知失败后的重试,可能会造成并发,导致订单数据不正常的问题。这里我是同步通知、异步通知的支付成功的处理逻辑中加了out_trade_no维度的分布式锁,并进行了订单的幂等性校验(判断这笔订单的支付状态是否为已支付)。