Nodejs ·

nodejs开发微信支付之接收退款申请通知

nodejs申请退款之后,微信服务器会将退款结果通知服务器,我们需要接收处理一下。特别说明:退款结果对重要的数据进行了加密,商户需要用商户秘钥进行解密后才能获得结果通知的内容。我不知道微信为什么单独要在这里进行加密处理,使得这个接口很麻烦,另外他给的解密步骤也很模糊:

  • 对加密串A做base64解码,得到加密串B
  • 对商户key做md5,得到32位小写key* ( key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 )
  • 用key*对加密串B做AES-256-ECB解密(PKCS7Padding)

解密后的加密串B字符编码是什么,没有指明,AES-256-ECB解密的偏移量是多少也没有说。我刚开始的时候解密得出加密串B,发现时乱码,顿时有种解错了的感觉,下面我来说一下使用nodejs如何解密微信支付退款通知req_info字段。

<xml>
<return_code>SUCCESS</return_code>
   <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
   <mch_id><![CDATA[10000100]]></mch_id>
   <nonce_str><![CDATA[TeqClE3i0mvn3DrK]]></nonce_str>
   <req_info><![CDATA[T87GAHG17TGAHG1TGHAHAHA1Y1CIOA9UGJH1GAHV871HAGAGQYQQPOOJMXNBCXBVNMNMAJAA]]></req_info>
</xml>

上面是微信返回的一个示例,其中req_info就是加密之后的内容,我们需要对它进行解密,我们开始按照微信给的步骤一步一步解密。下面代码中用到的一些封装方法在统一下单支付结果通知中已经写过了,我在这里直接使用。

解密之前,我们需要把xml格式转换为json格式:

let notionData = await exports.parseReqXmlData(req);//接收返回的xml内容
let notionResult = await exports.parseXml(notionData); //将xml进行解析为json格式

先进行接收,然后解析转码。

第一步,先对加密串A进行base64解密:

let req_info = Buffer.from(notionResult.req_info,'base64');

第二步,对key做md5,获取32位小写key*

let md5Key = common.md5(key).toLowerCase();//key做md5处理

第三步,将加密串做AES-256-ECB解密,这里需要用到crypto模块,我们将解密过程封装成一个方法,这样在调用时代码感觉会比较整齐,逻辑清晰些:

/**
 * aes解密微信回调通知
 * @param data 待解密内容
 * @param key 必须为32位私钥
 * @returns {string}
 */
exports.decryption = function (data, key, iv) {
    if (!data) {
        return "";
    }
    iv = iv || "";
    var clearEncoding = 'utf8';
    var cipherEncoding = 'base64';
    var cipherChunks = [];
    var decipher = crypto.createDecipheriv('aes-256-ecb', key, iv);
    decipher.setAutoPadding(true);
    cipherChunks.push(decipher.update(data, cipherEncoding, clearEncoding));
    cipherChunks.push(decipher.final(clearEncoding));
    return cipherChunks.join('');
};

解密方法封装好了就剩下调用了

let iv = Buffer.alloc(0);//设置偏移量
let decxml = exports.decryption(req_info,md5Key,iv);//解码

将偏移量设置为0填充的buffer。这样解析出来之后就是一个xml格式了,只不过他是以标签开头,我们解析的时候会报错,所以,在这里我将其转换为xml

let reg = new RegExp("root>", "g");
decxml = decxml.replace(reg,'xml>');
let finalResult = await exports.parseXml(decxml);

至此,解密完成。完整的步骤如下:

/**
 * 将退款xml结果格式化为json格式并解密
 * @param req
 * @param callback
 * @returns {Promise<void>}
 */
exports.wechatRefundNotion = async (req,key)=>{
    try{
        let notionData = await exports.parseReqXmlData(req);//接收返回的xml内容
        let notionResult = await exports.parseXml(notionData); //将xml进行解析为json格式
        console.log("req_info:"+notionResult.req_info);
        let req_info = Buffer.from(notionResult.req_info,'base64');//获取base64解码后的内容
        let md5Key = common.md5(key).toLowerCase();//key做md5处理
        let iv = Buffer.alloc(0);//设置偏移量
        let decxml = exports.decryption(req_info,md5Key,iv);//解码
        console.log(decxml);
        let reg = new RegExp("root>", "g");
        decxml = decxml.replace(reg,'xml>');
        let finalResult = await exports.parseXml(decxml);
        console.log(finalResult);
       return {
            success:true,
            data:finalResult
           }
    }catch (e){
        console.log(e);
         return {
            success:false,
            data:e
           }
    }
};

剩余的步骤就是验签和通知微信接收成功了,这两个步骤在支付结果通知中写过,不在赘述,需要的可以前往查看。
至于退款查询接口的封装和订单查询接口是一样的,这个可以在退款申请一文里写到

关于微信支付如何使用nodejs开发至此也就写完了,如果发现文中有误,请及时在下方评论区回复。

参与评论