本文是【浅析微信支付】系列文章的第六篇,主要讲解支付成功后,微信回调商户支付结果通知的处理。


浅析微信支付系列已经更新五篇了哟~,没有看过的朋友们可以看一下哦。

浅析微信支付:统一下单接口

浅析微信支付:微信公众号网页授权

浅析微信支付:开发前的准备

前面一章已经讲了如何调用统一下单接口和调起微信支付窗口,在调用下单接口时,我们会传入 异步接收微信支付结果通知的回调地址,顾名思义这个地址作用就是用来接收支付结果通知,当用户在前端支付成功后,微信服务器会自动调用此地址,然后商户再进行处理。

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><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";/*** 返回失败xml*/private String resFailXml = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";/*** 该链接是通过【统一下单API】中提交的参数notify_url设置,如果链接无法访问,商户将无法接收到微信通知。* 通知url必须为直接可访问的url,不能携带参数。示例:notify_url:“https://pay.weixin.qq.com/wxpay/pay.action”* <p>* 支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。* 对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。* (通知频率为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转换为mapMap<String, String> 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
Map<String, String> resultMap = WXPayUtil.xmlToMap(result);// 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。
WXPayUtil.isSignatureValid(resultMap, WXPayConstants.API_KEY);

从以上代码可以得知,微信是以流的方式来调用支付结果通知,流中数据格式为xml,所以需要先对流进行解析,然后再将xml转换为map,上面方法已经实现这个过程,有现成的代码可供参考,无需再重新编写代码。

需要注意的是,不论成功或者失败,必须向微信返回对应的返回值,如上方代码中的resSuccessXmlresFailXml,否则会引起重复调用的问题,在代码中我们应该规避风险。

2、对于支付单的处理

在收到支付结果后,我们会对系统中的支付单进行状态修改等操作,此时需要注意,如果微信返回失败,接口直接返回失败即可;

如果微信通知付款成功,返回时有一个 out_trade_no 参数,此参数为调用 统一下单接口 时传入微信的支付单号,可根据此参数取得对应的支付单,然后进行修改操作,若操作时出现异常,一定要向微信返回错误的xml代码,用微信的重试机制来二次回调,否则就需要记录通知信息,在本系统自动重试来解决。

在处理微信验证数据时,还需要注意微信最终返回的结果中是否使用了代金券,如果使用了代金券,还需要另行处理,此处先不详细描述,后面章节会详细解释代金券的操作。

结语

以上为 微信支付结果通知接口 的接收方式,它是一个微信服务自身控制的异步调用方法,在自身商户系统中需要处理很多异常,如网络抖动和服务异常等问题,所以尽量在商户系统中保存微信结果通知数据和增加失败重试机制,保证数据的正确性。

预告:下一篇文章 查询订单和关闭订单,敬请期待!!!

​如果想要提前一览源码的小伙伴,可以先看看我的 github,地址如下: https://github.com/YClimb/wxpay-sdk/blob/master/README.md

加作者私人微信,作者微信号如下 yclimb,标明 微信支付 可拉入微信支付讨论群与小伙伴一起探讨哦,一定要标明 微信支付 哦~

到此本文就结束了,关注公众号查看更多推送!!!



浅析微信支付:支付结果通知相关推荐

  1. 浅析微信支付:统一下单接口

    本文是[浅析微信支付]系列文章的第五篇,主要讲解如何调用统一下单接口生成预支付单及调起支付页面. 浅析微信支付系列已经更新四篇了哟-,没有看过的朋友们可以看一下哦. 浅析微信支付:微信公众号网页授权 ...

  2. 浅析微信支付:微信支付简单介绍(小程序、公众号、App、H5)

    本文是[浅析微信支付]系列文章的第二篇,主要讲解一下普通商户接入的支付方式以及其中的不同之处. 上篇文章讲了本系列的大纲,没有看过的朋友们可以看一下. 浅析微信支付:前篇大纲 微信支付是集成在微信客户 ...

  3. 浅析微信支付:申请退款、退款回调接口、查询退款

    本文是[浅析微信支付]系列文章的第八篇,主要讲解商户如何处理微信申请退款.退款回调.查询退款接口,其中有一些坑的地方,会着重强调. 浅析微信支付系列已经更新七篇了哟-,没有看过的朋友们可以看一下哦. ...

  4. 浅析微信支付:1前篇大纲

    以下会分几个步骤讲一下我学习微信支付的过程,也是一部辛酸史,也是希望朋友们不要再次跌进坑里,节省时间. 1.公司需要 如标题一般,公司来了这么个需求,需要接入微信支付,那就必须搞定他了,相信大部分的小 ...

  5. 浅析微信支付:开通社交立减金活动、创建立减金及领取使用的相关文档和源码

    本文是[浅析微信支付]系列文章的第十七篇,主要讲解在在微信平台中,如何创建优惠券,开通社交立减金,并为用户配置发送立减金. 上篇文章已经为大家讲解了如何在微信公众平台创建优惠券并为用户发券,这片文章是 ...

  6. 浅析微信支付:开通社交立减金活动、创建立减金及领取使用的相关文档和源码...

    本文是[浅析微信支付]系列文章的第十七篇,主要讲解在在微信平台中,如何创建优惠券,开通社交立减金,并为用户配置发送立减金. 上篇文章已经为大家讲解了如何在微信公众平台创建优惠券并为用户发券,这片文章是 ...

  7. 浅析微信支付:商户平台代金券或立减优惠开通、指定用户代金券发放、查询等

    本文是[浅析微信支付]系列文章的第十四篇,主要讲解在如何开通商户平台的代金券或立减优惠功能,商家向指定用户发送代金券,查询发送记录,代金券信息等. 浅析微信支付系列已经更新十四篇了哟-,没有看过的朋友 ...

  8. 浅析微信支付:开发前的准备

    本文是[浅析微信支付]系列文章的第三篇,主要会讲一下在开发前的一些注意事项. 浅析微信支付系列已经更新两篇了哟-,没有看过的朋友们可以看一下. 浅析微信支付:前篇大纲 浅析微信支付:微信支付简单介绍( ...

  9. 微信支付-接收返回通知结果

    2019独角兽企业重金招聘Python工程师标准>>> 前面我们说了统一下单(公众号同样适用只是参数有细微的差别,一定要注意) 接着说一下微信支付成功之后支付结果通用通知 该链接是通 ...

最新文章

  1. Chrome使用技巧和编辑框拖动怪问题。
  2. 自然语言处理(NLP)之从文本中提取时间
  3. 08查找满足条件的n个数
  4. 算法提高课-动态规划-树形DP-AcWing 1072. 树的最长路径:dfs写法
  5. scrapy-redis mysql_scrapy-redis 构建分布式爬虫,此片文章有问题。不要用
  6. shell与其他语言不同点
  7. gsonformat插件_吐血推荐珍藏的IDEA插件
  8. 熵权法 —— python
  9. 聚焦数智技术助力乡村振兴 京东云为乡村振兴注入“数智”力量
  10. 前端开发基础知识整理--web综合篇
  11. SOA企业需要考虑的事项
  12. 【Val】对于博客使用些许意见
  13. leetcode—20.二叉树构建相关题目leetcode总结
  14. Microsoft Recruit in Suzhou Branch (微软苏州招聘)
  15. mri计算机系统,MRI的一些基本介绍
  16. “AI芯片”通识_AI产品经理看这一篇就够了_团员分享_@书博
  17. 怎么理解幂等性[或者http幂等性]
  18. 讨论java类的图书推荐
  19. 出现身份验证错误,要求的函数不受支持(这可能是由于CredSSP加密Oracle修正)
  20. chroot 与 jail

热门文章

  1. 职业教育的春天 ——职业教育系列行研报告(一)
  2. c语言switch语句嵌套,浅谈c语言中switch语句的嵌套使用
  3. 管壁式换热器cad图纸_换热器之列管式换热器
  4. python练习题百度云_Python专项基础练习(字符串)练习题
  5. 如何扛住100亿次请求?后端架构应该这样设计!
  6. iOS学习—让View从下面弹出
  7. dmc预测控制 matlab,预测控制动态矩阵DMC算法研究分析及仿真.doc
  8. 中国内地摇滚歌手及代表作
  9. 我应该如何在CSDN问答提问?
  10. SEO新人如何做网站诊断和策划