收藏
回答

调用微信支付接口成功后后端会收到两次回调请求

调用微信支付接口成功后后端会收到两次回调请求,第一个请求是正常的,请求里可以拿到回调的信息,处理完后还会收到第二个请求,第二个请求中拿到的信息就是空了,解析这个空xml时代码就会报错了。下面上日志和代码

日志:

代码:

@ApiOperation("支付成功后的回调接口")
@RequestMapping(value = "/notify", produces = "application/json;charset=UTF-8")
public void payNotifyUrl(HttpServletRequest request, HttpServletResponse response) {
    String resultTemplate = "<xml><return_code><![CDATA[%s]]></return_code><return_msg><![CDATA[%s]]></return_msg></xml>";
    String returnCode;
    String returnMsg;
    try (BufferedReader reader = request.getReader()) {
        String line;
        StringBuilder input = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            input.append(line);
        }
        String xmlString = input.toString();
        log.info("----------------回调Xml:---------{}", xmlString);
        Map<String, String> map = CommonUtils.xmlToMap(xmlString);
        if (WxConstant.RESP_VALUE_SUCCESS.equals(map.get(WxConstant.FIELD_RESULT_CODE)) &&
                WxConstant.RESP_VALUE_SUCCESS.equals(map.get(WxConstant.FIELD_RETURN_CODE))) {
            // 检查签名,防止数据泄露导致出现“假通知”,造成资金损失。(微信支付推荐)
            if (CommonUtils.isSignatureValid(new TreeMap<>(map), WxConstant.API_KEY)) {
                // 更新订单状态,记录日志
                orderService.afterOrderPaid(map.get(WxConstant.FIELD_OUT_TRADE_NO));
                returnCode = WxConstant.RESP_VALUE_SUCCESS;
                returnMsg = WxConstant.RESP_MESSAGE_SUCCESS;
            } else {
                log.error("支付回调处理失败, 签名不正确,param: {}", map);
                returnCode = WxConstant.RESP_VALUE_FAIL;
                returnMsg = "签名不正确";
            }
        } else {
            returnCode = WxConstant.RESP_VALUE_FAIL;
            returnMsg = "参数校验不正确";
        }
        String result = String.format(resultTemplate, returnCode, returnMsg);
        log.info("----------------处理回调后返回的信息:---------{}", result);
        response.getWriter().write(result);
    } catch (Exception e) {
        log.error("支付回调处理异常", e);
        try (PrintWriter writer = response.getWriter()) {
            writer.write(String.format(resultTemplate, WxConstant.RESP_VALUE_FAIL, "回调处理异常"));
        } catch (Exception e2) {
            log.error("支付回调处理异常", e2);
        }
    }
}
回答关注问题邀请回答
收藏

2 个回答

  • Memory (私信不回复)
    Memory (私信不回复)
    2021-09-13

    微信支付为保证回调通知触达有效性,会有保障策略,在第一次通知如果网络链路返回无法连接或者状态不明,微信支付会换一条链路进行通知。此时可能会造成您这边收到两次通知。微信文档已强调同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。需要正确对自己数据进行状态唯一性处理。

    支付结果通知:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8

    应用场景

    支付完成后,微信会把相关支付结果及用户信息通过数据流的形式发送给商户,商户需要接收处理,并按文档规范返回应答。

    注意:

    1、同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。

    2、后台通知交互时,如果微信收到商户的应答不符合规范或超时,微信会判定本次通知失败,重新发送通知,直到成功为止(在通知一直不成功的情况下,微信总共会发起多次通知,通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m),但微信不保证通知最终一定能成功。

    3、在订单状态不明或者没有收到微信支付结果通知的情况下,建议商户主动调用微信支付【查询订单API】确认订单状态。

    特别提醒:

    1、商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄漏导致出现“假通知”,造成资金损失。

    2、当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。

    3、技术人员可登进微信商户后台扫描加入接口报警群,获取接口告警信息。


    2021-09-13
    有用 1
    回复 2
    • CoderLife
      CoderLife
      2021-09-13
      好的,我知道会多次通知这件事,但没想到会有通知参数为空的情况,谢谢回复
      2021-09-13
      回复
    • JiaJieChen
      JiaJieChen
      2022-05-19
      今天刚遇到这个问题,已经返回给微信成功了,没想到还会有概率出现第二第三次回调。真是巧合我们有一个打印业务也是放到这个回调接口,还没判断第几次,只要回调就打印。


      然后就修bug去了
      2022-05-19
      回复
  • 24K大白羊🐑
    24K大白羊🐑
    2021-09-12

    有可能会重复回调,要做好业务处理。

    空的情况直接过滤就可以。

    2021-09-12
    有用
    回复 2
    • CoderLife
      CoderLife
      2021-09-12
      哦哦 这是正常情况吗,那我就过滤掉好了,多谢多谢
      2021-09-12
      回复
    • 24K大白羊🐑
      24K大白羊🐑
      2021-09-14回复CoderLife
      可以算做正常情况吧,
      2021-09-14
      回复
登录 后发表内容