资讯专栏INFORMATION COLUMN

【Node.js 微信公众号实战】2.Node.js access_token的获取、存储及更新

adam1q84 / 2712人阅读

摘要:主要用于封装开发微信公众平台的所有方法。剩下的就是去微信公众平台接入验证了,在上一篇文章中有详细的教程,这里我就不再演示了三的获取存储及更新微信文档步骤在开始码代码之前,我们依然是先理清实现的思路,在开始编写实现代码。

一、写在前面的话

  上一篇文章中,我们使用 Node.js 成功的实现了接入微信公众平台功能。在这篇文章中,我们将实现微信公众平台一个非常重要的参数 access_token ,它是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用 access_token。

  在开始之前,让我们先按捺住自己激动的心情、调整好呼吸,因为我们要将上一篇文章的代码重新整理一下。一个好的项目结构,更能有助于我们理清业务逻辑以及将来维护代码的便捷。OK!

二、整理项目结构

1.打开我们的项目,并在项目中添加文件夹,命名为 wechat ,如图:

2.在 wechat 文件夹中添加文件并命名为 wechat.js。wechat.js 主要用于封装开发微信公众平台的所有方法。首先我们构建这个模块的结构,代码如下:

"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 定义了一种解析与执行模型。

 module.exports :暴露接口用于外部操作。实际上我们定义模块后,使用 node.js 的 require 引用时,node.js 会自动在我们定义的模块外层加入以下代码

/**
 * exports  module.exports 的一个简短的引用
 * require  用于引入模块
 * module   当前模块的引用
 * __filename  当前模块的文件名
 * __dirname   当前模块的目录名
 */
(function (exports, require, module, __filename, __dirname) {
    //自定义模块的代码块
})();

相信对于有过 javascript 开发经验的同学,上面的代码并不陌生。我们可以将它理解为一个闭包,是一个匿名方法的调用,避免污染全局变量。

小知识:

  在上面的代码中,除了我们所使用的 module.exports 对象,还有另一个用于暴露接口的 变量 exports (官方文档将 module.exports 称为对象,exports 称为 属性,我在这里也就这样称呼了),那么 module.exports 与 exports 有什么区别呢?

  module.exports 对象是由模块系统创建的,exports 变量是在模块的文件级别作用域内有效的,它在模块被执行前被赋于 module.exports 的值。——来自Node.js官方文档

  也就是说 exports 是 module.exports 的引用,而 module.exports 才是真正用于暴露接口的对象。 exports 赋值的所有属性与方法都赋值给了 module.exports 对象。

  如果 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);

嗯!这样代码看着是不是舒服多了呢。

剩下的就是去微信公众平台接入验证了,在上一篇文章中有详细的教程,这里我就不再演示了

三、access_token的获取、存储及更新

1.微信文档步骤

  在开始码代码之前,我们依然是先理清实现的思路,在开始编写实现代码。打开 微信帮助文档 ,点击左侧菜单中的开始开发,点击其子菜单获取access_token,如图:

通过上面的 API 的描述,我们总结出以下步骤:

实现 https Get 请求

获取 access_token 并存储 如果 当前 access_token 过期则更新

2.access_token的获取、存储及更新 代码实现

  整理好思路后我们就按照上一节的步骤去实现。通过帮助文档我们将用于请求微信API 的请求地址与参数,存放到 config.json 文件。

  其中 appid 与 secret 两个参数 位于 微信公众平台 左侧菜单的基本配置中,如图:

开发者密码 点击重置,用手机微信扫面二维码后便可得到。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);
    });    
});

  这样我们就大功告成了!

  文章源代码:https://github.com/SilenceHVK... 。对文章有不正确之处,请给予纠正。github源代码请顺手给个 Star,最后感谢您的阅读。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92121.html

相关文章

  • Node.js 微信公众实战】4.Node.js 微信消息管理

    摘要:消息推送也是微信公众号开发更为有趣的功能,涉及到文本消息图片消息语音消息视频消息音乐消息以及图文消息。在文件中创建文件用于消息的管理。 一、写在前面的话   当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应。   消息推送也是微信公众号开发更为有趣的功能,涉及到文本消息、图片消...

    lewinlee 评论0 收藏0
  • Node.js 微信公众实战】3.Node.js 自定义微信菜单

    摘要:一写在前面的话上一篇文章中,我们使用成功的实现了的获取存储以及更新,这篇文章我们来实现微信的自定义菜单功能。二自定义微信菜单微信文档步骤在开始码代码之前,我们依然是先理清实现的思路,再开始编写实现代码。 一、写在前面的话   上一篇文章中,我们使用 Node.js 成功的实现了access_token 的获取、存储以及更新,这篇文章我们来实现微信的自定义菜单功能。showImg(htt...

    Barry_Ng 评论0 收藏0
  • Node.js微信公众开发

    摘要:在微信开发者工具中调试和一定要正确域名一定是备案的绑定域名需要的放在服务器上的位置一定要正确参考微信公众号开发文档 node微信公众号开发 概览 key value 项目名称 node微信公众号开发 项目描述 使用node编写接口,前后端分离获取签名数据 开发者 leinov 发布日期 2018-11-07 仓库 github地址 安装&使用 下载 gi...

    OnlyLing 评论0 收藏0
  • Node微信公众开发 - 定时获取最新文章同步到MySQL数据库

    摘要:方案二通过微信公众号平台提供的接口定时获取数据,然后插入到小程序数据库中。和可在微信公众平台开发基本配置页中获得需要已经成为开发者,且帐号没有异常状态。 0、介绍 本文源码:https://github.com/Jameswain/... ​ showImg(https://segmentfault.com/img/remote/1460000015441409?w=660&h...

    0x584a 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<