node微信掃碼支付(一)

版權聲明:本文爲博主原創文章,未經博主容許不得轉載。javascript

概述

目前微信官方的微信支付demo沒有node版本,這幾天一直折騰微信支付,當作筆記記錄下來;
參考資料微信支付官方文檔php

簽名

微信支付的簽名採用MD5加密,下面微信支付的簽名算法,及統一下單:
首先先創建一個wechatPay.js 文件(在該文件中包括簽名算法,統一下單等)前端

/**
** 引入依賴包
**/
var config = require('../config');
var request = require("request");
var moment = require('moment'),
    _ = require('underscore'),
    https = require('https'),
    fs = require('fs'),
    URL = require('url'),
    CryptoJS = require("crypto-js"),
    jsontoxml = require('jsontoxml'),
    xml2js = require('xml2js');
var crypto = require('crypto');

/**
** 簽名算法
**/
var generateSign = exports.genrateSign = function(obj) {

    var tmpObj = {};  // 取非空的key
    _.each(obj, function(value, key){
        if(value) {
            tmpObj[key] = value;
        }
    });
    var keys = _.keys(tmpObj); // key 字典排序
    keys = keys.sort();

    var tmpArr = [];
    _.each(keys, function(key) {
        tmpArr.push(key + "=" + tmpObj[key])
    })
    tmpArr.push("key=" + config.wxmcn.mcnsecret);  // //key爲在微信商戶平臺(pay.weixin.qq.com)-->帳戶設置-->API安全-->密鑰設置
    var tmpStr = tmpArr.join('&'); // 拼接字符串
    var sign = crypto.createHash('md5').update(tmpStr, 'utf8').digest('hex');
    return sign.toUpperCase();
}

//統一下單,獲取code_url後期生成二維碼
var paysign = exports.paysign = function(params,callback) {
    if(_.isEmpty(params)) {
        callback('參數不能爲空');
    }

    var currentTime = moment().valueOf().toString();
    var nonce_str = [
        config.wxmcn.mcnid,
        currentTime
    ].join('');   //  隨機字符串
    var mch_billno = [
        config.wxmcn.mcnid,
        moment().format("YYYYMMDD"),
        moment().unix()
    ].join('');   // 訂單號


    var ret = {
        appid: config.H5.appid,
        body: params.body,  // 商品描述
        attach: params.attach,  // 用戶的身份intid
        mch_id: config.wxmcn.mcnid,  // 商戶號
        nonce_str: nonce_str,  // 隨機字符串
        notify_url:params.notify_url,  // 通知地址
        out_trade_no:mch_billno,  // 商戶訂單號
        spbill_create_ip:params.spbill_create_ip,  //  終端ip
        total_fee:params.total_fee,  // 標價金額
        trade_type:params.trade_type  // 交易類型
    };
    if(!_.isEmpty(params.openid)){
        _.extend(ret,{openid: params.openid});
    }

    var sign = generateSign(ret);
    _.extend(ret,{sign: sign});

    var body = jsontoxml(ret);
    body = '<xml>' + body + '</xml>';
    request({
        url:'https://api.mch.weixin.qq.com/pay/unifiedorder',
        method: 'POST',
        body: body
    },function (err, response, body)
    {
        if (!err && response.statusCode == 200)
        {
           // xml2js將返回xml 轉換成json,可是後面都是都數組
            xml2js.parseString(body, function(err, json) {
                if (err) {
                    callback(new Error("解析xml報錯"));
                } else {
                    var result = formMessage(json.xml); // 轉換成正常的json 數據
                    if(result.return_code === 'SUCCESS' && result.result_code === 'SUCCESS') {
                        callback(null,result);
                    }else {
                        callback(new Error('wechat err'))
                    }
                }
            })

        }
    });
};

// 將xml2js 轉換成json數據進一步轉換
var formMessage = function(result) {
    var message = {};
    if (typeof  result === 'object') {
        var keys = Object.keys(result);

        for (var i = 0; i < keys.length; i++) {
            var item = result[keys[i]];
            var key = keys[i];
            if (!(item instanceof Array) || item.length === 0) {
                continue;
            }
            if (item.length === 1) {
                var val = item[0];
                if (typeof  val === 'object') {
                    message[key] = formMessage(val);
                } else {
                    message[key] = (val || '').trim();
                }
            } else {
                message[key] = [];
                for (var j = 0, k = item.length; j < k; j++) {
                    message[key].push(formMessage(itemp[j]));
                }
            }
        }
    }
    return message;
}

在router 調用

本次開發用的express框架,建立一個wxpayRouter.js(包括獲取微信支付的二維碼等)java

/*
** 引入依賴
*/
var express = require('express');
var wxPayRouter = express.Router();
var mongoose = require('mongoose'),
    ObjectId = mongoose.Schema.Types.ObjectId;
var wechatPay = require('./wechatpay')

var URL = require('url'),
    async = require('async'),
    _ = require('underscore'),
    qr = require('qr-image'),
    jsontoxml = require('jsontoxml'),
    moment = require('moment');
   

wxPayRouter.get('/order',function(req, res, next){
    var params = URL.parse(req.url, true);
    var queryParams = req.query;
          total_fee = queryParams.total_fee;  // 前端金額
       

    var status = 400,
        errmsg = "";

    if(_.isEmpty(total_fee)) {
        errmsg = 'total_fee is empty';
    }
    if(errmsg){
        return res.end({status: status, msg: errmsg});
    }


    async.auto({
       
        getCodeUrl: function(callback) {
            var condition = {body: '訂單名稱',attach:'附加信息'};  //  attach 會在支付成功的後的原封不動的返回
            if(!_.isEmpty(total_fee)) {
                _.extend(condition, {total_fee: total_fee});
            }
            _.extend(condition, {spbill_create_ip: tools.getLocalIP(),trade_type: 'NATIVE'});
            // notify_url 爲微信回調的地址,將支付成功的信息以數據流的形式返回
            _.extend(condition,{notify_url: 'http://49727c15.ngrok.io/wxpay/orderpay'});

            wechatPay.paysign(condition, function(err, result){
               if(err) {
                   return callback(new Error('connect wechat service is fail'));
               }
               callback(null,result );

            });
        }
    }, function(err, results) {

        if(err) {
            return res.end({status: status, msg: err.message});
        }
        var data = results.getCodeUrl;

        if(_.isEmpty(data)){
            status = 404;
        }else{
            status = 200;
        }

        res.end({status: status, data: data});
    })
});
module.exports = wxPayRouter;

後臺微信的支付接口已經完成,前端調用order接口同時須要將支付金額一併傳遞過來;而後後臺返回相關信息,code_url經過第三方工具生成二維碼,用戶掃碼便可完成支付。node

相關文章
相關標籤/搜索