支付成功异步通知接口


订单支付成功后,平台会发送异步通知到订单携带的notify_url,推送方式为 HTTP POST

特别提醒:接收异步通知的notify_url必须为可直接访问的URL,不能携带参数,不能有session、csrf等各种登录验证

请求参数:

字段名称 字段类型 必填参数 说明
return_code int(1) Y 1:支付成功
total_fee int(16) Y 金额。单位:分
out_trade_no string(32) Y 用户端自主生成的订单号
payjs_order_id string(32) Y PAYJS 订单号
transaction_id string(32) Y 微信用户手机显示订单号
time_end string(32) Y 支付成功时间
openid string(32) Y 用户OPENID标示,本参数没有实际意义,旨在方便用户端区分不同用户
attach string(127) N 用户自定义数据
mchid string(16) Y 商户号
type string(16) N 支付类型。微信订单不返回该字段;支付宝订单返回:alipay
sign string(32) Y 数据签名 详见签名算法

提示:

  1. 异步通知以原始表单方式 application/x-www-form-urlencoded POST 推送,不是以json方式推送
  2. 接收通知的服务器请在3秒钟内响应(http状态码200则标记通知成功,其它状态码则标记通知失败,推送结束)
  3. 为保障推送到达率,系统可能多次进行通知推送,请做好去重逻辑
  4. 推送可能增加参数,请做好冗余处理
  5. 商户系统对于支付结果通知的内容要验签,避免异步通知被伪造
  6. 验签时,所有接收参数都参与验签
  7. 通知频率(秒):0,15,30,180,1800,3600。超过1小时后如需推送,可以在后台手动补发
  8. 异步通知过程中,如果该订单接收到check接口的成功查询,则异步通知在执行完当前任务后终止,不再继续通知

接收异步通知流程示例:

<?php
$data = $_POST;

if($data['return_code'] == 1){
    // 1.验签逻辑

    // 2.验重逻辑

    // 3.自身业务逻辑

    // 4.返回 success 字符串(http状态码为200)
    echo 'success';
}

?>

php

<?php
$data = $_POST;

if($data['return_code'] == 1){
    // 1.验签逻辑

    // 2.验重逻辑

    // 3.自身业务逻辑

    // 4.返回 success 字符串(http状态码为200)
    echo 'success';
}

?>

python

# 以flask为例

from flask import Flask
from flask import request
import logging
app = Flask(__name__)
app.logger.setLevel(logging.DEBUG)

@app.route('/api[您的接口]/',methods=['GET','POST'])
def api():
    if request.method == 'POST':
        data = request.form
        if data.get('return_code') == '1':
            # 1.验签逻辑

            # 2.验重逻辑

            # 3.自身业务逻辑

            # 4.返回 success 字符串(http状态码为200)
            return 'success!'
    return 'fail!'


if __name__ == '__main__':
    app.run()

node

//基于expressjs的回调示例
//异步通知,/notifyCheck为你的自定义回调地址
router.post('/notifyCheck', function(req, res, next) {
  var params=req.body;
  if(pay.notifyCheck(params)==true){ //签名校验成功
    if(params.return_code==1){
      //业务逻辑
      res.send('success');
    }else{
      res.status(404);
    }
  }else{
    //校验失败
    res.status(404);
  }
});

java

// 完整代码:https://github.com/payjs-cn/demo-java
public Object payjsNotify(NotifyDTO notifyDTO){
    Map<String,String> notifyData = new HashMap<>();
    notifyData.put("return_code",notifyDTO.getReturn_code());
    notifyData.put("total_fee",notifyDTO.getTotal_fee());
    notifyData.put("out_trade_no",notifyDTO.getOut_trade_no());
    notifyData.put("payjs_order_id",notifyDTO.getPayjs_order_id());
    notifyData.put("transaction_id",notifyDTO.getTransaction_id());
    notifyData.put("time_end",notifyDTO.getTime_end());
    notifyData.put("openid",notifyDTO.getOpenid());
    notifyData.put("attach",notifyDTO.getAttach());
    notifyData.put("mchid",notifyDTO.getMchid());

    String sign = sign(notifyData, PayjsConfig.key);
    if(sign.equals(notifyDTO.getSign())){
        // 验签通过,这里修改订单状态


        return "success";
    }

    return "failure";
}

csharp

// 完整项目地址:https://github.com/payjs-cn/sdk-csharp

Payjs payjs = new Payjs("your mchid","your key");

//获取post参数
var param = Request.Form.ToDictionary(s => s.Key, s => s.Value);

//示例参数
// string orderid = param.ContainsKey("out_trade_no")?param["out_trade_no"].ToString():"";
// string total_fee = param.ContainsKey("total_fee") ? param["total_fee"].ToString() : "";
// string attach = param.ContainsKey("attach") ? param["attach"].ToString() : "";
//这里需要对订单数据做基本校验,可以检查当前订单号是否存在,金额和自定义数据是否匹配等

//post 参数字典转为<string,string>
var dic = new Dictionary<string, string>();
foreach (var keyPair in param)
{
    dic.Add(keyPair.Key,keyPair.Value.ToString());
}

//对签名校验
string sign = param["sign"];
if (!payjs.notifyCheck(dic))
{
    return "sign error";
}

//校验成功,进入自身业务逻辑(需在3s内响应
//若超过3s,可以把自身业务放后端(比如通过tcp或者udp通知后端服务),然后这里就直接return success

return "success";

powered by Gitbook最后更新: 2020-10-27