zoukankan      html  css  js  c++  java
  • Live2D 看板娘

    一 access_token基本概念

      定义:access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。

      时效性:access_token的有效期目前为2个小时(7200秒),需定时刷新,重复获取将导致上次获取的access_token失效。

      针对时效性问题的处理方法:

        1 让系统每隔2个小时去刷新一次票据,这样无论合适我们内部调用接口,这个票据始终是最新的;

        2 为了方便频繁调用,我们需要把票据存储在一个地方,并且是唯一的一个地方,这个地方要被所有的子文件都能访问到,一定不能存在内存中。

      公众平台的API调用所需的access_token的使用及生成方式说明:

        1、建议公众号开发者使用中控服务器统一获取和刷新Access_token,其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致access_token覆盖而影响业务;

        2、目前Access_token的有效期通过返回的expire_in来传达,目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新access_token。在刷新过程中,中控服务器对外输出的依然是老access_token,此时公众平台后台会保证在刷新短时间内,新老access_token都可用,这保证了第三方业务的平滑过渡;

        3、Access_token的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新access_token的接口,这样便于业务服务器在API调用获知access_token已超时的情况下,可以触发access_token的刷新流程。

        公众号可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。调用接口时,请登录“微信公众平台-开发-基本配置”提前将服务器IP地址添加到IP白名单中,点击查看设置方法,否则将无法调用成功。

      接口调用请求说明:

        https请求方式: GET
        https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

      获取票据次数上限:每日2000次

    二 获取access_token逻辑代码示例

      新建项目文件wechat,项目目录结构如下:

      app.js文件代码:

    'use strict';
    // 引入模块
    var Koa = require('koa');
    var path = require('path');
    //引入中间件
    var generator = require('./model/generator');
    var util = require('./libs/util');
    //引入文本文件
    var wechat_file = path.join(__dirname, './config/wechat.txt');
    // 声明对象字面量config 用于存储配置信息、读取写入票据的方法
    var config = {
        wechat: {
            appID: 'wx044125d0a173dd15',
            appSecret: '21295f049b49fe324d7302186c294fe7',
            token: 'beijingjiangweiwechatlearntokenvalueabcdefg',
            getAccessToken:function(){
                return util.readFileAsync(wechat_file);
            },
            saveAccessToken:function(data){
                data = JSON.stringify(data);
                return util.writeFileAsync(wechat_file, data);
            }
        }
    }
    
    // 实例化Koa的web服务器
    var app = new Koa();
    //传入配置参数
    app.use(generator(config.wechat));
    //监听3100端口
    app.listen(3100);
    //console.log('listening:3100');

      generator.js文件代码:

    'use strict';
    // 引入模块
    var sha1 = require('sha1');
    var Promise = require('bluebird');
    var request = Promise.promisify(require('request'));
    
    //增加url配置项
    var prefix = 'https://api.weixin.qq.com/cgi-bin/';
    var api = {
        accessToken: prefix + 'token?grant_type=client_credential'
    }
    
    //利用构造函数生成实例 完成票据存储逻辑
    function weChat(opts) {
        var that = this;
        this.appID = opts.appID;
        this.appSecret = opts.appSecret;
        this.getAccessToken = opts.getAccessToken;
        this.saveAccessToken = opts.saveAccessToken;
        //获取票据的方法
        this.getAccessToken()
            .then(function(data) {
                //从静态文件获取票据,JSON化数据,如果有异常,则尝试更新票据
                try {
                    data = JSON.parse(data);
                } catch (e) {
                    return that.updateAccessToken();
                }
                //判断票据是否在有效期内,如果合法,向下传递票据,如果不合法,更新票据
                if (that.isValidAccessToken(data)) {
                    Promise.resolve(data);
                } else {
                    return that.updateAccessToken();
                }
            })
            //将拿到的票据信息和有效期信息存储起来
            .then(function(data) {
                console.log(data);
                that.access_token = data.access_token;
                that.expires_in = data.expires_in;
    
                that.saveAccessToken(data);
            })
    };
    
    //在weChat的原型链上增加验证有效期的方法
    weChat.prototype.isValidAccessToken = function(data) {
        //进行判断,如果票据不合法,返回false
        if (!data || !data.access_token || !data.expires_in) {
            return false;
        }
        //拿到票据和过期时间的数据
        var access_token = data.access_token;
        var expires_in = data.expires_in;
        //获取当前时间
        var now = (new Date().getTime());
        //如果当前时间小于票据过期时间,返回true,否则返回false
        if (now < expires_in) {
            return true;
        } else {
            return false;
        };
    };
    
    //在weChat的原型链上增加更新票据的方法
    weChat.prototype.updateAccessToken = function() {
        var appID = this.appID;
        var appSecret = this.appSecret;
        var url = api.accessToken + '&appid=' + appID + '&secret=' + appSecret;
    
        return new Promise(function(resolve, reject) {
            //使用request发起请求
            request({
                url: url,
                json: true
            }).then(function(response) {
                var data = response.body;
                var now = (new Date().getTime());
                var expires_in = now + (data.expires_in - 20) * 1000;
                //把新票据的有效时间赋值给data
                data.expires_in = expires_in;
                resolve(data);
            })
        })
    };
    
    // 建立中间件函数并暴露出去
    module.exports = function(opts) {
        //实例化weChat()函数
        var wechat = new weChat(opts);
        return function*(next) {
            console.log(this.query);
            var token = opts.token;
            var signature = this.query.signature;
            var nonce = this.query.nonce;
            var timestamp = this.query.timestamp;
            var echostr = this.query.echostr;
            // 进行字典排序
            var str = [token, timestamp, nonce].sort().join('');
            // 进行加密
            var sha = sha1(str);
            // 判断加密后的值是否等于签名值
            if (sha === signature) {
                this.body = echostr + '';
            } else {
                this.body = 'wrong';
            }
        }
    };

      util.js文件代码:

    'use strict';
    //引入模块
    var fs = require('fs');
    var Promise = require('bluebird');
    //读取票据信息
    exports.readFileAsync = function(fpath, encoding) {
        return new Promise(function(resolve, reject) {
            fs.readFile(fpath, encoding, function(err, content) {
                if (err) {
                    reject(err);
                }else{
                    resolve(content);
                };
            });
        });
    };
    //写入票据信息
    exports.writeFileAsync = function(fpath, content) {
        return new Promise(function(resolve, reject) {
            fs.writeFile(fpath, content, function(err) {
                if (err) {
                    reject(err);
                }else{
                    resolve();
                };
            });
        });
    };

      实现获取微信票据的全部代码,我都贴了出来,现在来对照代码捋顺一遍逻辑,在app.js文件中,我们声明了对象字面量config对象,把微信的appID、appSecret、token以及获取(getAccessToken)和更新(saveAccessToken)票据的方法,然后把config对象传给了generator即generator.js文件weChat()函数,注意generator.js文件中下方暴露出来的函数,首先是实例化了weChat()函数,首先把config对象传递过来的配置信息放在自身的属性上,然后调用自身获取票据的方法getAccessToken()去读取文本文件里的token值,如果值是合法的,就向下传递,如果不合法就更新票据,更新时调用updateAccessToken()方法,请求微信服务的url地址,从地址里拿到返回的JSON数据,把数据中的票据时间缩短20秒,然后赋给数据本身,然后再把数据向下传递,最终会拿到一个有效的票据结果,然后把票据的两个字段access_token、expires_in赋值给自身,并调用saveAccessToken()方法,把票据结果存储到文本文件中,票据获取的过程就完成了。

      在终端启动app.js文件,启动魔法隧道,微信测试号接口配置也没有问题的话,我们可以看到在wechat.txt文件中,已经写入票据信息了。

      备注:实现获取票据的过程,我只贴了代码示例,里面的各个依赖模块,需要手动安装(使用npm install)。

     注意:因为官方文档是处于更新状态的,所以后面关于微信公众号的知识点,可能跟最新的文档有一定的差异,所以开发的时候还是要以最新的文档为准。

  • 相关阅读:
    java编译错误No enclosing instance of type TestFrame is accessible. Must qualify the allocation with an enclosing instance of type TestFrame (e.g. x.new A(
    java 2中创建线程方法
    动态规划基本思想
    关于eclipse编译一个工程多个main函数
    java Gui初识
    Eclipse中java项目的打包
    java 播放声音
    把资源文件夹导入到eclipse中
    Java建立JProgressBar
    How to grant permissions to a custom assembly that is referenced in a report in Reporting Services
  • 原文地址:https://www.cnblogs.com/jiangtengteng/p/6905795.html
Copyright © 2011-2022 走看看