Nodejs ·

nodejs接收微信支付通知结果

统一下单中讲到了微信支付的统一下单,统一下单完成后就是客户端的事情了,根据返回的信息来调起微信支付,完成付款。当付款完成后,微信服务器会post支付结果通知我们,此接口需要单独来写,并且需要按照微信文档的要求来返回数据。

接收通知一般会进行如下步骤:
- 接收post传输的xml格式数据
- 解析xml,转为json
- 签名验证
- 返回结果通知微信服务器接收成功

接收post传输的xml格式数据

接收xml格式的数据和接收json的方式是不一样的,下面我们来看一下该如何接收微信支付通知结果的xml格式数据,我们还是将它写在pay.js文件中:

/**
 * 解析通过post传递过来的xml信息
 * @param req
 * @returns {Promise<any>}
 */
exports.parseReqXmlData = (req)=>{
    let notionData = "";
    req.setEncoding('utf8');
    req.on('data', (chunk)=>{
        notionData += chunk;
    });
    return new Promise((resolve,reject)=>{
        req.on("end",()=>{
            resolve(notionData)
        });
        req.on("error",(e)=>{
            reject(e)
        })
    })


};

我们不能用之前的req.body或req.query来进行接收了,要通过监听data来获取数据,上面我们将其封装成了promise的方式来进行返回数据。

签名验证

接收到数据之后要做的就是解析,解析方法在统一下单中已经写过了,在这不在赘述,解析完成之后需要进行验签操作,以防恶意调用此接口进行支付结果的伪造,验签和签名的步骤差不多,就是对比一下传递过来的参数和签名是否一致,下面我们来看一下具体的实现方法

/**
 * 校验返回结果签名是否正确
 * @param obj 待校验对象
 * @param key  商户平台设置的密钥key
 * @returns {boolean} 返回结果 true为正确,false为不正确
 */
exports.checkPayResultSign = (obj,key)=>{
    try{
        let tempObj = Object.assign({},obj);
        let resultSign = tempObj.sign;
        delete tempObj.sign;
        tempObj = exports.getWechatSign(tempObj,key);
        if(tempObj){
            return resultSign == tempObj.sign
        }else{
            console.log("checkPayResultSign:签名校验异常");
            return false;
        }
    }catch(e){
        console.log(e);
        return  false
    }
};

如上方法就是进行签名校验,其实就是将传递过来的参数保存起来,然后在对参数进行签名,两次对比是否一致,签名方法在统一下单中已经写过了,需要的小伙伴可以看一下。

返回结果通知微信服务器接收成功

验签成功后要做的就是构造xml格式数据,通知微信服务器我们接收成功了。

/**
 * 微信支付成功后,微信服务器主动回调方法,
 */
router.post("/payNotice",async (req,res)=>{
try{
    let key="sdkfnowemcoiwem4"//这里我将key写死在这里了,正常是需要从数据库或配置文件中读取
    let xmlPost = await exports.parseReqXmlData(req)//解析获取xml
    let formatNotion = await exports.parseXml(xmlPost);//将xml格式解析为json格式

    let result= "";
    if(formatNotion.return_code === "SUCCESS"){
        console.log(formatNotion);

        let checkPayResultSign = exports.checkPayResultSign(formatNotion,key);
        console.log("支付返回信息签名校验:"+checkPayResultSign);
        if(checkPayResultSign){
            result = `<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>`;
        }else{
            result = `<xml><return_code><![CDATA[FALSE]]></return_code><return_msg><![CDATA[FALSE]]></return_msg></xml>`;
        }
    }else{
        result = `<xml><return_code><![CDATA[FALSE]]></return_code><return_msg><![CDATA[FALSE]]></return_msg></xml>`;
    }
    res.writeHead(200, {'Content-Type': 'text/xml'});
    res.end(result)

}catch(e){
    console.log("回调通知异常:"+JSON.stringify(e));
    res.json({
        success:false
    });
}

catch里面我返回的是json格式,这个其实是为非正常调用返回的,正常微信调用是不会走catch的,所以不用过多考虑它,返回xml格式需要设置header,将Content-Type设置为text/xml,以告诉对方我们发送的是xml格式的数据。

至此如何接收微信支付通知结果就介绍完了,后续会继续介绍订单查询等后续接口

参与评论