摘要:本文是浅析微信支付系列文章的第六篇,主要讲解支付成功后,微信回调商户支付结果通知的处理。微信支付支付回调接口该链接是通过统一下单中提交的参数设置,如果链接无法访问,商户将无法接收到微信通知。
本文是【浅析微信支付】系列文章的第六篇,主要讲解支付成功后,微信回调商户支付结果通知的处理。
浅析微信支付系列已经更新五篇了哟~,没有看过的朋友们可以看一下哦。
浅析微信支付:统一下单接口
浅析微信支付:微信公众号网页授权
浅析微信支付:开发前的准备
前面一章已经讲了如何调用统一下单接口和调起微信支付窗口,在调用下单接口时,我们会传入 异步接收微信支付结果通知的回调地址,顾名思义这个地址作用就是用来接收支付结果通知,当用户在前端支付成功后,微信服务器会自动调用此地址,然后商户再进行处理。
1、支付结果通知以下为接口官方解释:
支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。 对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。 (通知频率为15/15/30/180/1800/1800/1800/1800/3600,单位:秒) 注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。 特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄漏导致出现“假通知”,造成资金损失。 技术人员可登进微信商户后台扫描加入接口报警群。
支付结果通知接口文档地址:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
需要注意的事项有以下几点:
1. 该链接是通过【统一下单API】中提交的参数notify_url设置,如果链接无法访问,商户将无法接收到微信通知。 2. 通知url必须为直接可访问的url,不能携带参数,也就是必须使用外网接口地址,不能使用本地调试地址 3. 商户需要接收处理,并返回应答。如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。 4. 通知频率为15/15/30/180/1800/1800/1800/1800/3600,单位:秒 5. 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 6. 特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄漏导致出现“假通知”,造成资金损失。
PS:推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
关于具体的签名和接收通知代码如下:
package imall.controller.wx;
package ...
/**
* 微信支付Controller
*
* @author yclimb
* @date 2018/6/15
*/
@Api
@RestController
@RequestMapping("/weixin/pay")
public class WXPayController extends BaseController {
// 需要注入的一些service
/**
* 返回成功xml
*/
private String resSuccessXml = " ";
/**
* 返回失败xml
*/
private String resFailXml = " ";
/**
* 该链接是通过【统一下单API】中提交的参数notify_url设置,如果链接无法访问,商户将无法接收到微信通知。
* 通知url必须为直接可访问的url,不能携带参数。示例:notify_url:“https://pay.weixin.qq.com/wxpay/pay.action”
*
* 支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。
* 对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。
* (通知频率为15/15/30/180/1800/1800/1800/1800/3600,单位:秒)
* 注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
* 推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
* 特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,防止数据泄漏导致出现“假通知”,造成资金损失。
*
* @author yclimb
* @date 2018/6/15
*/
@ApiOperation(value = "微信支付|支付回调接口", httpMethod = "POST", notes = "该链接是通过【统一下单API】中提交的参数notify_url设置,如果链接无法访问,商户将无法接收到微信通知。")
@RequestMapping("/wxnotify")
public void wxnotify(HttpServletRequest request, HttpServletResponse response) {
String resXml = "";
InputStream inStream;
try {
inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
WXPayUtil.getLogger().info("wxnotify:微信支付----start----");
// 获取微信调用我们notify_url的返回信息
String result = new String(outSteam.toByteArray(), "utf-8");
WXPayUtil.getLogger().info("wxnotify:微信支付----result----=" + result);
// 关闭流
outSteam.close();
inStream.close();
// xml转换为map
Map resultMap = WXPayUtil.xmlToMap(result);
boolean isSuccess = false;
if (WXPayConstants.SUCCESS.equalsIgnoreCase(resultMap.get(WXPayConstants.RESULT_CODE))) {
WXPayUtil.getLogger().info("wxnotify:微信支付----返回成功");
if (WXPayUtil.isSignatureValid(resultMap, WXPayConstants.API_KEY)) {
// 订单处理 操作 orderconroller 的回写操作?
WXPayUtil.getLogger().info("wxnotify:微信支付----验证签名成功");
// 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
resXml = resSuccessXml;
isSuccess = true;
} else {
WXPayUtil.getLogger().error("wxnotify:微信支付----判断签名错误");
}
} else {
WXPayUtil.getLogger().error("wxnotify:支付失败,错误信息:" + resultMap.get(WXPayConstants.ERR_CODE_DES));
resXml = resFailXml;
}
// 付款记录修改 & 记录付款日志
// 回调方法,处理业务 - 修改订单状态
WXPayUtil.getLogger().info("wxnotify:微信支付回调:修改的订单===>" + resultMap.get("out_trade_no"));
int updateResult = ...;
if (updateResult > 0) {
WXPayUtil.getLogger().info("wxnotify:微信支付回调:修改订单支付状态成功");
} else {
WXPayUtil.getLogger().error("wxnotify:微信支付回调:修改订单支付状态失败");
}
} catch (Exception e) {
WXPayUtil.getLogger().error("wxnotify:支付回调发布异常:", e);
} finally {
try {
// 处理业务完毕
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
} catch (IOException e) {
WXPayUtil.getLogger().error("wxnotify:支付回调发布异常:out:", e);
}
}
}
}
验证是否本商户返回的正确通知:
// xml转换为map MapresultMap = WXPayUtil.xmlToMap(result); // 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。 WXPayUtil.isSignatureValid(resultMap, WXPayConstants.API_KEY);
从以上代码可以得知,微信是以流的方式来调用支付结果通知,流中数据格式为xml,所以需要先对流进行解析,然后再将xml转换为map,上面方法已经实现这个过程,有现成的代码可供参考,无需再重新编写代码。
需要注意的是,不论成功或者失败,必须向微信返回对应的返回值,如上方代码中的resSuccessXml、resFailXml,否则会引起重复调用的问题,在代码中我们应该规避风险。
2、对于支付单的处理在收到支付结果后,我们会对系统中的支付单进行状态修改等操作,此时需要注意,如果微信返回失败,接口直接返回失败即可;
如果微信通知付款成功,返回时有一个 out_trade_no 参数,此参数为调用 统一下单接口 时传入微信的支付单号,可根据此参数取得对应的支付单,然后进行修改操作,若操作时出现异常,一定要向微信返回错误的xml代码,用微信的重试机制来二次回调,否则就需要记录通知信息,在本系统自动重试来解决。
在处理微信验证数据时,还需要注意微信最终返回的结果中是否使用了代金券,如果使用了代金券,还需要另行处理,此处先不详细描述,后面章节会详细解释代金券的操作。
结语以上为 微信支付结果通知接口 的接收方式,它是一个微信服务自身控制的异步调用方法,在自身商户系统中需要处理很多异常,如网络抖动和服务异常等问题,所以尽量在商户系统中保存微信结果通知数据和增加失败重试机制,保证数据的正确性。
预告:下一篇文章 查询订单和关闭订单,敬请期待!!!
如果想要提前一览源码的小伙伴,可以先看看我的 github,地址如下: https://github.com/YClimb/wxpay-sdk/blob/master/README.md
加作者私人微信,作者微信号如下 yclimb,标明 微信支付 可拉入微信支付讨论群与小伙伴一起探讨哦,一定要标明 微信支付 哦~
到此本文就结束了,关注公众号查看更多推送!!!
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/72063.html
摘要:本文是浅析微信支付系列文章的第十篇,主要讲解如何使用沙箱环境来测试微信支付。图为微信支付仿真测试系统后简称仿真系统的简化原理图。沙箱说明微信支付沙箱环境,是提供给微信支付商户的开发者,用于模拟支付及回调通知。 本文是【浅析微信支付】系列文章的第十篇,主要讲解如何使用沙箱环境来测试微信支付。 浅析微信支付系列已经更新十篇了哟~,没有看过的朋友们可以看一下。 浅析微信支付:下载对账单和资...
摘要:浅析微信支付前篇大纲本文是浅析微信支付系列文章的第一篇,主要会介绍一下为何写下这个系列以及对于微信支付的一点小经验,与君共勉。下面讲一下我是如何去学习微信支付的。 浅析微信支付:前篇大纲 本文是【浅析微信支付】系列文章的第一篇,主要会介绍一下为何写下这个系列以及对于微信支付的一点小经验,与君共勉。 以下会分几个步骤讲一下我学习微信支付的过程,也是一部辛酸史,也是希望朋友们不要再次跌进...
摘要:注意交易时间超过一年的订单无法提交退款微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。 本文是【浅析微信支付】系列文章的第八篇,主要讲解商户如何处理微信申请退款、退款回调、查询退款接口,其中有一些坑的地方,会着重强调。 浅析微信支付系列已经更新七篇了哟~,没有看过的朋友们可以看一下哦。 浅析微信支付:查询订单和关闭订单 浅析微信支付:支...
摘要:本文是浅析微信支付系列文章的第五篇,主要讲解如何调用统一下单接口生成预支付单及调起支付页面。浅析微信支付系列已经更新四篇了哟,没有看过的朋友们可以看一下哦。 本文是【浅析微信支付】系列文章的第五篇,主要讲解如何调用统一下单接口生成预支付单及调起支付页面。 浅析微信支付系列已经更新四篇了哟~,没有看过的朋友们可以看一下哦。 浅析微信支付:微信公众号网页授权 浅析微信支付:开发前的准备 ...
摘要:本文是浅析微信支付系列文章的第七篇,主要讲解微信商户平台的订单查询和关闭接口的使用。查询订单以下为微信官方的查询订单文档应用场景该接口提供所有微信支付订单的查询,商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。 本文是【浅析微信支付】系列文章的第七篇,主要讲解微信商户平台的订单查询和关闭接口的使用。 浅析微信支付系列已经更新六篇了哟~,没有看过的朋友们可以看一下哦。 ...
阅读 3902·2021-10-09 09:41
阅读 2928·2021-10-08 10:18
阅读 2434·2021-09-10 10:51
阅读 2886·2021-09-10 10:50
阅读 1136·2021-09-09 09:33
阅读 3648·2021-09-06 15:14
阅读 3277·2019-08-30 11:06
阅读 3475·2019-08-29 14:04