【Node.js 微信公衆號實戰】2.Node.js access_token的獲取、存儲及更新

1、寫在前面的話

  上一篇文章中,咱們使用 Node.js 成功的實現了接入微信公衆平臺功能。在這篇文章中,咱們將實現微信公衆平臺一個很是重要的參數 access_token ,它是公衆號的全局惟一接口調用憑據,公衆號調用各接口時都需使用 access_token。javascript

  在開始以前,讓咱們先按捺住本身激動的心情、調整好呼吸,由於咱們要將上一篇文章的代碼從新整理一下。一個好的項目結構,更能有助於咱們理清業務邏輯以及未來維護代碼的便捷。OK!
Are you ready?html

2、整理項目結構

1.打開咱們的項目,並在項目中添加文件夾,命名爲 wechat ,如圖:
這裏寫圖片描述java

2.在 wechat 文件夾中添加文件並命名爲 wechat.js。wechat.js 主要用於封裝開發微信公衆平臺的全部方法。首先咱們構建這個模塊的結構,代碼以下:node

'use strict' //設置爲嚴格模式

//構建 WeChat 對象 即 js中 函數就是對象
var WeChat = function(config){
    //設置 WeChat 對象屬性 config
    this.config = config;
    
    //設置 WeChat 對象屬性 token
    this.token = config.token;
}

//暴露可供外部訪問的接口
module.exports = WeChat;

 嚴格模式:是在 ECMAScript 5 中引入的概念。嚴格模式是爲 Javascript 定義了一種解析與執行模型。git

 module.exports :暴露接口用於外部操做。實際上咱們定義模塊後,使用 node.js 的 require 引用時,node.js 會自動在咱們定義的模塊外層加入如下代碼es6

/**
 * exports  module.exports 的一個簡短的引用
 * require  用於引入模塊
 * module   當前模塊的引用
 * __filename  當前模塊的文件名
 * __dirname   當前模塊的目錄名
 */
(function (exports, require, module, __filename, __dirname) {
    //自定義模塊的代碼塊
})();

相信對於有過 javascript 開發經驗的同窗,上面的代碼並不陌生。咱們能夠將它理解爲一個閉包,是一個匿名方法的調用,避免污染全局變量。github

小知識:

  在上面的代碼中,除了咱們所使用的 module.exports 對象,還有另外一個用於暴露接口的 變量 exports (官方文檔將 module.exports 稱爲對象,exports 稱爲 屬性,我在這裏也就這樣稱呼了),那麼 module.exports 與 exports 有什麼區別呢?express

  module.exports 對象是由模塊系統建立的,exports 變量是在模塊的文件級別做用域內有效的,它在模塊被執行前被賦於 module.exports 的值。——來自Node.js官方文檔npm

  也就是說 exports 是 module.exports 的引用,而 module.exports 纔是真正用於暴露接口的對象。 exports 賦值的全部屬性與方法都賦值給了 module.exports 對象。json

  若是 module.exports 與 exports 將值賦值給了相同的屬性,則按照賦值的前後順序,取最後一個賦值;若是咱們給 module.exports 賦值的是一個對象,則會覆蓋 exports 的全部方法與屬性。

  所以咱們在暴露接口的使用上,若是隻是單一屬性或方法的話,建議使用exports.屬性/方法,要是導出多個屬性或方法或使用對象構造方法,建議使用 module.exports。

  具體詳解能夠點擊查看該文章 -> Module.exports和exports的區別

3.爲 WeChat 對象添加一個方法 auth,並將 app.js 中的驗證方法粘貼進去

'use strict' //設置爲嚴格模式

const crypto = require('crypto'); //引入加密模塊

//構建 WeChat 對象 即 js中 函數就是對象
var WeChat = function(config){
    //設置 WeChat 對象屬性 config
    this.config = config;

    //設置 WeChat 對象屬性 token
    this.token = config.token;
}

/**
 * 微信接入驗證
 */
WeChat.prototype.auth = function(req,res){
     //1.獲取微信服務器Get請求的參數 signature、timestamp、nonce、echostr
        var signature = req.query.signature,//微信加密簽名
            timestamp = req.query.timestamp,//時間戳
                nonce = req.query.nonce,//隨機數
            echostr = req.query.echostr;//隨機字符串

        //2.將token、timestamp、nonce三個參數進行字典序排序
        var array = [this.token,timestamp,nonce];
        array.sort();

        //3.將三個參數字符串拼接成一個字符串進行sha1加密
        var tempStr = array.join('');
        const hashCode = crypto.createHash('sha1'); //建立加密類型 
        var resultCode = hashCode.update(tempStr,'utf8').digest('hex'); //對傳入的字符串進行加密

        //4.開發者得到加密後的字符串可與signature對比,標識該請求來源於微信
        if(resultCode === signature){
            res.send(echostr);
        }else{
            res.send('mismatch');
        }
}

//暴露可供外部訪問的接口
module.exports = WeChat;

4.整理 app.js 文件的中的代碼,以下:

const express = require('express'), //express 框架 
      wechat  = require('./wechat/wechat'), 
       config = require('./config');//引入配置文件

var app = express();//實例express框架

var wechatApp = new wechat(config); //實例wechat 模塊

//用於處理全部進入 3000 端口 get 的鏈接請求
app.get('/',function(req,res){
    wechatApp.auth(req,res);
});

//監聽3000端口
app.listen(3000);

嗯!這樣代碼看着是否是舒服多了呢。機智如我

剩下的就是去微信公衆平臺接入驗證了,在上一篇文章中有詳細的教程,這裏我就再也不演示了

就是這麼懶

3、access_token的獲取、存儲及更新

1.微信文檔步驟

  在開始碼代碼以前,咱們依然是先理清實現的思路,在開始編寫實現代碼。打開 微信幫助文檔 ,點擊左側菜單中的開始開發,點擊其子菜單獲取access_token,如圖:
獲取access_token

獲取access_token 幫助文檔

經過上面的 API 的描述,咱們總結出如下步驟:

  1. 實現 https Get 請求
  2. 獲取 access_token 並存儲 若是 當前 access_token 過時則更新

2.access_token的獲取、存儲及更新 代碼實現

  整理好思路後咱們就按照上一節的步驟去實現。經過幫助文檔咱們將用於請求微信API 的請求地址與參數,存放到 config.json 文件。

  其中 appid 與 secret 兩個參數 位於 微信公衆平臺 左側菜單的基本配置中,如圖:
微信公衆平臺 - 基本配置

APPID 與 AppSecret

開發者密碼 點擊重置,用手機微信掃面二維碼後即可獲得。config.json 代碼以下

{
    "token":"wechat",
    "appID":"wx154f********764da",
    "appScrect":"59de4266*******8dbe9de4b798cd372",
    "apiDomain":"https://api.weixin.qq.com/",
    "apiURL":{
        "accessTokenApi":"%scgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"
    }
}

因爲微信 API 請求鏈接的域名是公用的,咱們將它提出來,在請求地址中使用 %s(字符串) 佔位符佔位。

  微信全部請求鏈接都是 https 協議,很幸運的是 Node.js 系統包中爲咱們提供了 https 的包,因爲後面的請求會屢次用到 https ,所以咱們將它封裝爲一個公用的方法,以便之後的使用,再次打開 wechat.js 在構造方法中,引入 https 模塊,並在構造函數內部添加 requestGet 方法

//用於處理 https Get請求方法
    this.requestGet = function(url){
        return new Promise(function(resolve,reject){
            https.get(url,function(res){
                var buffer = [],result = "";
                //監聽 data 事件
                res.on('data',function(data){
                    buffer.push(data);
                });
                //監聽 數據傳輸完成事件
                res.on('end',function(){
                    result = Buffer.concat(buffer,buffer.length).toString('utf-8');
                    //將最後結果返回
                    resolve(result);
                });
            }).on('error',function(err){
                reject(err);
            });
        });
    }
提示:

    npm 提供了不少用於請求的工具包,好比 request ( 安裝命令 npm install request ) 等。這裏我只是用系統包去作請求處理。

  因爲 https 是異步請求的,我在這裏面使用了 ES6 的 Promise 對象

  完成了 requestGet方法後,咱們的第1步驟也就完成了。下面開始第2步,獲取 access_token 並存儲 若是 當前 access_token 過時則更新。

  在這以前我是想將 access_token 的存儲位置依然放在 config.json 文件中,因爲 access_token 在更新後 須要將文件重寫,可能容易形成 config.json 文件的格式的紊亂,所以在 wechat 中從新建立一個 accessToken.json 文件用於存儲 access_token
這裏寫圖片描述

{
    "access_token":"",
    "expires_time":0
}

   其中 access_token 用於存儲 咱們 GET 請求後access_token 的值,expires_time 用於存儲 access_token 的過時時間,保存爲時間戳。

  在 wechat.js 引入 fs 模塊用於操做文件、util 工具模塊用於處理佔位符、 accessToken.json 文件

'use strict' //設置爲嚴格模式

const crypto = require('crypto'), //引入加密模塊
       https = require('https'), //引入 htts 模塊
        util = require('util'), //引入 util 工具包
accessTokenJson = require('./access_token'); //引入本地存儲的 access_token

//構建 WeChat 對象 即 js中 函數就是對象
var WeChat = function(config){
    //設置 WeChat 對象屬性 config
    this.config = config;
    //設置 WeChat 對象屬性 token
    this.token = config.token;
    //設置 WeChat 對象屬性 appID
    this.appID = config.appID;
    //設置 WeChat 對象屬性 appScrect
    this.appScrect = config.appScrect;
    //設置 WeChat 對象屬性 apiDomain
    this.apiDomain = config.apiDomain;
    //設置 WeChat 對象屬性 apiURL
    this.apiDomain = config.apiURL;

    //用於處理 https Get請求方法
    this.requestGet = function(url){
        return new Promise(function(resolve,reject){
            https.get(url,function(res){
                var buffer = [],result = "";
                //監聽 data 事件
                res.on('data',function(data){
                    buffer.push(data);
                });
                //監聽 數據傳輸完成事件
                res.on('end',function(){
                    result = Buffer.concat(buffer,buffer.length).toString('utf-8');
                    //將最後結果返回
                    resolve(result);
                });
            }).on('error',function(err){
                reject(err);
            });
        });
    }
}

  在 wechat.js 添加獲取 access_token 的方法 getAccessToken

/**
 * 獲取微信 access_token
 */
WeChat.prototype.getAccessToken = function(){
    var that = this;
    return new Promise(function(resolve,reject){
        //獲取當前時間 
        var currentTime = new Date().getTime();
        //格式化請求地址
        var url = util.format(that.apiURL.accessTokenApi,that.apiDomain,that.appID,that.appScrect);
        //判斷 本地存儲的 access_token 是否有效
        if(accessTokenJson.access_token === "" || accessTokenJson.expires_time < currentTime){
            that.requestGet(url).then(function(data){
                var result = JSON.parse(data); 
                if(data.indexOf("errcode") < 0){
                    accessTokenJson.access_token = result.access_token;
                    accessTokenJson.expires_time = new Date().getTime() + (parseInt(result.expires_in) - 200) * 1000;
                    //更新本地存儲的
                    fs.writeFile('./wechat/access_token.json',JSON.stringify(accessTokenJson));
                    //將獲取後的 access_token 返回
                    resolve(accessTokenJson.access_token);
                }else{
                    //將錯誤返回
                    resolve(result);
                } 
            });
        }else{
            //將本地存儲的 access_token 返回
            resolve(accessTokenJson.access_token);  
        }
    });
}

  在 app.js 中添加新的監聽連接用於測試 咱們獲取的token

//用於請求獲取 access_token
app.get('/getAccessToken',function(req,res){
    wechatApp.getAccessToken().then(function(data){
        res.send(data);
    });    
});

獲取access_token的效果圖

  這樣咱們就大功告成了!

年輕人恭喜你

  文章源代碼:https://github.com/SilenceHVK... 。對文章有不正確之處,請給予糾正。github源代碼請順手給個 Star,最後感謝您的閱讀。

相關文章
相關標籤/搜索