1. 程式人生 > >單頁面應用接入微信填坑之二(微信支付Nodejs)

單頁面應用接入微信填坑之二(微信支付Nodejs)

先記錄一下正常接入微信支付步驟

微信公眾號配置:

1. 開通微信公眾號
這裡就沒什麼要講的了
2.伺服器配置
進入微信公眾平臺->開發->基本配置->伺服器配置,之後填寫伺服器地址和令牌,並按照微信官方教程配置即可。下面是我自己的一段Node.js版本的簡單伺服器配置:
var http = require("http");
var url = require("url");
var crypto = require('crypto');
var token = 'abc123'; //令牌
function getQuery(name,str) {
    var
reg = new RegExp(name+'=([^&]*)'); var matches = reg.exec(str); if (matches) { return matches[1]; } return ''; } /** *監聽請求 */ function onRequest(request,response){ var urlParams = url.parse(request.url); var result = verify(urlParams.query); response.writeHead(200
,{"Content-type":"text/plain; charset=UTF-8"}); response.write(result); response.end(); } function verify(query) { var signature = getQuery('signature',query); var timestamp = getQuery('timestamp',query); var nonce = getQuery('nonce',query); var echostr = getQuery('echostr',query); var
arr = [token,timestamp,nonce]; arr.sort(); var tempStr = arr.join(''); var sha1 = crypto.createHash('sha1'); var resultCode = sha1.update(tempStr,'utf-8').digest('hex'); if (resultCode === signature) { return echostr; } return 'nomatch'; } http.createServer(onRequest).listen(80);
3.js域名設定
進入微信公眾平臺->公眾號設定->功能配置,之後填寫業務域名、js介面安全域名和網頁授權域名,這三個域名的作用設定時看官方解釋即可。
4.獲取開發者密碼與AppId
進入微信公眾平臺->基本配置,設定或獲取開發者密碼與AppId,在獲取使用者user_info中將用到。

微信支付商戶平臺配置:

公眾平臺微信支付公眾號支付授權目錄、掃碼支付回撥URL配置入口已於8月1日遷移至商戶平臺(pay.weixin.qq.com)

1.支付授權目錄配置
微信支付商戶平臺->產品中心->開發配置->支付配置->新增授權目錄,在微信中呼叫支付時必須在新增的目錄中,否則將無法支付。
2.設定API金鑰
微信支付商戶平臺->賬戶中心->API安全->設定API金鑰,將金鑰記下(建立統一支付訂單時需要)

開發配置:

1.通過微信授權獲取使用者openid

第一步:使用者同意授權,獲取code
訪問下面的連結:

'https://open.weixin.qq.com/connect/oauth2/authorize?appid='+微信公眾號AppId+'&redirect_uri='+跳轉地址+'wxoauth&response_type=code&scope=snsapi_userinfo#wechat_redirect'

還記得我們在上面微信公眾號配置->js域名設定,填寫的網頁授權域名嗎?當我們使用上面的連結獲取到code之後微信就會在URL query中攜帶著code跳轉到網頁授權域名。

第二步:通過code換取網頁授權access_token
通過GET方式獲取到ACCESS_TOKEN:

getWXToken: function(code) {
   let reqUrl = 'https://api.weixin.qq.com/sns/oauth2/access_token?';
    let params = {
        appid: wxConfig.appid,//微信公眾號AppId
        secret: wxConfig.appSecret,//微信公眾號開發者密碼
        code: code,//上一步獲取到的code
        grant_type: 'authorization_code'
    };
    let options = {
        method: 'get',
        url: reqUrl + CommonUtil.json2RequestParam(params)
    };
    return new Promise((resolve, reject) => {
        request(options, function(err, res, body) {
            if (res) {
                resolve(body);
            } else {
                reject(err);
            }
        })
    });
},

在上面的程式碼中用到了request庫,access_token和使用者openid就存在於body中.如果不需要獲取使用者資訊,那麼到這一步就可以了。

第三步:拉取使用者資訊(需scope為 snsapi_userinfo)

getWXUserInfo: function(AccessToken, openId) {
    let reqUrl = 'https://api.weixin.qq.com/sns/userinfo?';
    let params = {
        access_token: AccessToken,//上一步獲取到的AccessToken
        openid: openId,//上一步獲取到的使用者openId
        lang: 'zh_CN'
    };
    let options = {
        method: 'get',
        url: reqUrl + CommonUtil.json2RequestParam(params)
    };
    return new Promise((resolve, reject) => {
        request(options, function(err, res, body) {
            if (res) {
                resolve(body);
            } else {
                reject(err);
            }
        });
    })
},
2.建立微信統一訂單
//微信支付相關
var fs = require('fs');
var path = require('path');
var wxConfig = require('../config/weixin');
var util = require('./weixinUtil');
var request = require('request');
var md5 = require('MD5');

function WXPay() {

    if (!(this instanceof WXPay)) {
        return new WXPay(arguments[0]);
    };

    this.options = arguments[0];
    this.wxpayID = { appid: wxConfig.appid, mch_id: wxConfig.mch_id };
};

WXPay.mix = function() {
    switch (arguments.length) {
        case 1:
            var obj = arguments[0];
            for (var key in obj) {
                if (WXPay.prototype.hasOwnProperty(key)) {
                    throw new Error('Prototype method exist. method: ' + key);
                }
                WXPay.prototype[key] = obj[key];
            }
            break;
        case 2:
            var key = arguments[0].toString(),
                fn = arguments[1];
            if (WXPay.prototype.hasOwnProperty(key)) {
                throw new Error('Prototype method exist. method: ' + key);
            }
            WXPay.prototype[key] = fn;
            break;
    }
};

WXPay.mix('option', function(option) {
    for (var k in option) {
        this.options[k] = option[k];
    }
});

WXPay.mix('sign', function(param) {
    var str = '';
    var arr = [];
    for (var name in param) {
        if (param[name] != null && param[name] != '') {
            arr.push(name + '=' + param[name]);
        }
    }
    arr.sort();
    str = arr.join('&');
    str = str + '&key=' + wxConfig.mch_key;
    return md5(str).toUpperCase();
});

WXPay.mix('createWCPayOrder', function(order) {
    order.spbill_create_ip = order.spbill_create_ip.match(/\d+.\d+.\d+.\d+/)[0];//請求Ip
    order.trade_type = "JSAPI";
    order.nonce_str = order.nonce_str || util.generateNonceString();//隨機字串
    util.mix(order, this.wxpayID);//加入公眾號AppId和微信支付商戶Id
    order.sign = this.sign(order);
    var self = this;
    return new Promise(function(resolve, reject) {
        self.requestUnifiedOrder(order, function(err, data) {
            if (err) {
                reject(err);
            } else {
                if (data.return_code == 'SUCCESS' && data.result_code == 'SUCCESS') {
                    var resParam = {
                        "appId": data.appid, //公眾號名稱,由商戶傳入     
                        "timeStamp": Math.floor(Date.now() / 1000) + "", //時間戳,自1970年以來的秒數     
                        "nonceStr": data.nonce_str, //隨機串     
                        "package": "prepay_id=" + data.prepay_id,
                        "signType": "MD5" //微信簽名方式:     
                    };
                    resParam.paySign = self.sign(resParam);
                    resolve(resParam);
                } else {
                    reject(data);
                }
            }
        }, function(err) {
            reject(err);
        });
    });
});

WXPay.mix('requestUnifiedOrder', function(order, fn, errFn) {
    request({
        url: "https://api.mch.weixin.qq.com/pay/unifiedorder",
        method: 'POST',
        body: util.buildXML(order)
    }, function(err, response, body) {
        if (err) {
            errFn();
        } else {
            console.log('body:' + body);
            util.parseXML(body, fn);
        }
    });
});
exports = module.exports = WXPay;

以上程式碼是一個封裝好的建立微信統一支付的類,使用方法如下:

var wxpay = new WeixinPay();
var wxOrder = await wxpay.createWCPayOrder({
    openid: ctx.session.openid,//使用者openid
    body: '購買商品',
    detail: '購買商品',
    out_trade_no: orderDetail.code, //平臺內部訂單號
    total_fee: parseInt(orderDetail.totalPrice*100,10),//總價格
    spbill_create_ip: ctx.ip,//ip
    notify_url: 'http://baebae.cn/api/order/paynotify'//支付回撥地址
});

接下來將wxOrder返回給前端即可。

3.前端呼叫微信支付
wxPay: function(order, fn) {
    if (typeof window.WeixinJSBridge === 'undefined') {
        return;
    }
    window.WeixinJSBridge.invoke(
        'getBrandWCPayRequest',
        order,
        function(res) {
            if (res.err_msg == "get_brand_wcpay_request:ok") {
                fn(true);
            } else {
                fn(false);
            }
        }
    );
},

通過將上一步wxOrder傳入上面的方法即可喚起微信支付,當用戶支付後微信將回調上一步建立訂單時傳入的回撥地址。

4.回撥處理
payNotify: async function(ctx) {
    var body = ctx.request.body;
    if (body.return_code == 'SUCCESS' && body.result_code == 'SUCCESS') {
        // 支付成功處理
    }
    var message = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
    ctx.body = message;
},

這個方法便是回撥處理方法,當請求中的return_code和result_code皆為SUCCESS表示支付成功,之後還應返回一段狀態XML(即上述程式碼中的message)給微信表示已獲取到微信提示,否則微信將以某種策略一直請求回撥地址。微信官方文件: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

遇到的坑

我有兩個支付頁面,當我按照上面的步驟做了之後發現在我的手機中(IOS)支付沒有問題,但是當在安卓手機中卻無法正常支付。後來弄了很久,發現在上述:微信支付商戶平臺配置->支付授權目錄時並沒有寫完全(只寫了一個目錄)。

相關推薦

頁面應用入微支付Nodejs

先記錄一下正常接入微信支付步驟 微信公眾號配置: 1. 開通微信公眾號 這裡就沒什麼要講的了 2.伺服器配置 進入微信公眾平臺->開發->基本配置->伺服器配置,之後填寫伺服器地址和令牌,並按照微信官方教程配置即可。下面是我自己的一

頁面應用入微之一分享

起因:使用react+react-router做了一個單頁面應用,需接入微信支付與分享等功能。由於是個人第一次接觸微信接入加之是單頁面應用所以遇到了很多問題。所以這裡記一下其中之一:分享功能! 微信官方說法: 所有需要使用JS-SDK的頁面必須先注入配置

Android第二十一篇天貓開源框架V_layout使用總結

基本使用流程網上案例很多,大多都是貼上複製,當然也沒有問題,只要讀者能夠明白使用的流程即可,筆者也是從網上一步一步按部就班去學習,梳理並最終運用到自身專案當中去 在學習以及運用過程中碰到些

分享到

1、註冊了公眾平臺測試賬號,下載了jssdk。 而後開始了,生成自定義分享卡片之旅。 坑點一: 生成簽名的url一定要是當前頁面的url,所以 正確的姿勢是:(url一定是從前端傳過來的location.href)       public function getSignPackage

小程式:佈局適配方案rpx、px、vw、vh

因為小程式是以微信為平臺執行的,可以同時執行在android與ios的裝置上,所以不可避免的會遇到佈局適配問題,特別是在iphone5上,因為螢幕尺寸小的緣故,也是適配問題最多的機型,下面就簡單介紹幾種適配方法。 rpx適配 rpx是小程式中

php curl返回false記-curl呼叫建立自定義選單返回false

首先宣告一點,這個錯誤可能在你的開發生涯中不會遇到,除非你直接複製了微信公眾平臺的api地址。不過這應該算是php中curl擴充套件的一個bug,為什麼是bug呢?讓我們仔細來看。 下邊是示例程式碼,程式碼的功能是呼叫微信公眾平臺的建立自定義選單介面來建立自定義選單。 建

小遊戲

1、註冊微信小程式賬號 http://mp.weixin.qq.com 2、下載開發工具 3、新建專案,選擇小程式 4、選好目錄、填寫專案名稱、可選是否建立demo或是空專案啟動 5、若不選擇“建立普通快速啟動模板”會提示如下 在目錄下新建game.jsongame.

小程式:text空格符號以及省略號

1、text的空格符 首先需要設定<text> 控制元件的decode值 decode可以解析的有&nbsp; &lt; &gt; &amp; &

小程式--2016.12.21 更新

今天又一次更新,繼續填坑了。。 更新概述 新增分享、模板訊息、客服訊息、掃一掃、帶引數二維碼(當前僅限開發者和體驗者使用)等功能新增 4 個新 API, 2個新元件拓展了 10 個元件屬性,新增 6 個元件事件修復數十個 API 以及元件 bug,優化部分互動體驗開發者工

小程式登入獲取openid、unionid

在微信小程式中,因為各種各樣的原因我們會需要獲取到使用者的openid或者unionid下面就簡單來講一下在小程式中如何獲取openid和unionid。 步驟一:微信登入獲取登入憑證

小程式:cover-view

在一些情況下,我們需要對map、video、canvas、camera這些微信小程式的原生控制元件,進行自定義,比如在camera上新增一個矩形線框作為拍照區域,這時我們就需要使用到cover-view

Web3 --- js驗證碼外掛GVerify

轉載:網路 !(function(window, document) { function GVerify(options) { //建立一個圖形驗證碼物件,接收options物件為引數 this.options = { //預設opti

Web4 --- web server大概解釋

Web Server中文名稱叫網頁伺服器或web伺服器。web伺服器也稱為WWW伺服器,主要功能是提供網上資訊瀏覽服務。 Web伺服器可以解析HTTP協議。當Web伺服器接收到一個HTTP請求,會返回一個HTTP響應,例如返回一個HTML頁面。為了處理一個請求,Web伺服器可以響應一個靜態頁面或圖片,進行頁

Android第二十使用友盟社會化分享的碰到的

最近有個專案又要使用分享功能模組,況且之前也整合過,於是乎趁現在專案沒有啟動,就提前預熱了一把,本想著兩個鐘頭搞定,然而儘管之前整合過一次,筆者發現過段時間之後還是像剛剛整合一樣,故寫下這篇博文加以記錄。 1.在使用友盟分享面板的時候出現面板無法彈出,只是

Android第十三篇教你一招搞定專案混淆配置

# Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in D:\Androi

java-mongo複雜管道聚合aggregate的分頁、allowDiskUse、統計

List<DBObject> aggregateQuery = new ArrayList<DBObject>(); BasicDBObject groupHeapNum = new BasicDBObject("heapNum","$heapNum"); BasicDBObjectB

小程序初探常見語法 VS vue常見問題點擊不生效,數據綁定

數據驅動 一點 驅動 win -1 沒有 html cat been 最近在調研微信小程序開發,對於一個前端小白來說,在各種框架都還用不熟的情況下,再來開發小程序確實還是不容易。 小程序出來之初,聽過演講,看過一點點兒視頻,感覺和angular語法有點相似(PS:那是也是只

ios開發--仿自定義表情鍵盤

lai signed avi 創建 不能 url div load mps 先附上demo:https://github.com/hgl753951/CusEmoji.git 效果圖如下: 先說下具體的實現功能: 1,本地加載了一些H5的代碼,直接使用webview的lo

java的公眾號開發三支付

步驟一:我們需要將微信支付所需要的引數組裝好,然後傳送請求。 所需要的引數在微信支付開發文件中就可以找到我們所必須的11個引數。 步驟二:然後在回撥函式中處理我們支付後的業務邏輯。 /** * * 獲得威微信支付的相關引數

企業嵌入自定義專案useId校驗登陸使用者合法性

好久沒有寫部落格了,最近有一點小收穫,來記錄一下。免的以後使用的時候又找不到。 最近,公司需要用企業微信整合內部專案。原本以為是另外一個大神的事,結果落到我頭上了。慚愧花費了兩天時間,哎。。。 博主在這裡走了不少彎路。在這建議大家,儘量能閱讀官方文件再入手。我百度攻略耗費半天時間,然而收穫甚微。 好了,