缓存公众号的access_token

全篇共 2433 字。按500字/分钟阅读,预计用时 4.9 分钟。总访问 1014 次,日访问 1 次。

在这篇 开启微信公众号开发者模式 中,我们已经通过比对signature来双向验证微信服务器和自己的服务器,接下来就是和具体业务相关的事务了。无论你要接收还是回复用户向公众号发送的各种类型的消息,还是你要在微信网页端项目中拿到用户的授权(获取用户基本信息),还是调用微信网页端中丰富的JS-SDK接口,如照相、上传图片、录音、支付等功能。

问题与解决方案

实现这一切业务功能的前提是获取access_token,通过它调用各种各样的接口。但它也有有效期,目前官方文档说access_token的有效期是2小时,未来还会改变。而且它还有调用频次的限制,你不能每次在需要它时就获取新的access_token,你应该把它缓存起来,过期后才更新它。缓存access_token的方式有很多,你可以把它存放在某个文本文件中,也可以把它存放在数据库中,当然还有其它方式,这取决于你自己。而我选择后者的方案。

更新access_token的方案有两种,一种叫主动更新,另一种叫被动更新。主动更新就是有一个定时任务专门监测是否过期,当access_token快过期时,主动获取新的。被动更新就是当需要access_token才能正常使用的业务发现它已经过期了,才去更新它。我选择的后者的方案。

下面我就详细谈谈我是如何做的。

数据库与缓存

我使用MySQL数据库,我创建了一个新的数据库:wechat。

// 创建新的数据库,名叫wechat
create database wechat;

// 这个命令用来显示所有的数据库
// 可以看到新创建的wechat数据库
show databases;

// 如果不小心创建错了,可以用这个命令删掉它
drop database wechat;

// 在wechat中创建表之前,先“进入”wechat数据库
use wechat;

如果你想学习更多MySQL的知识,可以一会到文章末尾扩展阅读中找找。我在wechat数据库中创建了名为 wechat_access_token 的表,就在这个表里缓存access_token值以及它的下一次过期日期。

create table wechat_access_token (
access_token text,
expires text
) default charset = 'utf8';

插入一条记录,作为access_token和expires的初始值,其中expires存储的是access_token下一次失效的日期,所以初始化时只要设置现在的日期即可。

获取access_token

我把获取access_token的代码逻辑封装到了一个函数中,因为未来在别处还会用到它。该函数返回一个Promise实例,就能很方便用 Asynv/Await 语法调用它了。

() => {
  return new Promise(async (resolve, reject) => {
    // 先从数据表拿到缓存的access_token和过期日期
    const accessTokensInDB = await util.query('wechat', `select * from wechat_access_token`);
    const accessTokenInDB = accessTokensInDB[0];
    // 比对过期日期和现在的日期
    if (Date.now() < +accessTokenInDB.expires) {
    	// 如果比现在日期要远,说明没过期
      resolve(accessTokenInDB.access_token);
    } else {
      // 过期了,被动更新。
      // 这里的AppID和AppSecret需要替换成你自己的,其中AppID是可以公开的
      const APPID = 'wxa6686e2d7d734068';
      const APPSECRET = '****************************';
      // 调用接口获取新的access_token和它的有效时间
      // 这里没有捕获可能出现的异常,因为异常能够向上扩散,我在外层捕获它。
      const TOKEN = await util.getRequest(`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`);
      if (!TOKEN.access_token || !TOKEN.expires_in) {
        reject(TOKEN);
        return;
      }
      // 更新缓存。
      // 这里注意接口返回的有效期是以秒为单位,比如7200代表有效期为两个小时,我用毫秒存储到期日期,所以要乘1000。
      await util.query('wechat', `update wechat_access_token set access_token = '${TOKEN.access_token}', expires = '${Date.now() + TOKEN.expires_in * 1000}'`);
      resolve(TOKEN.access_token);
    }
  });
}

好啦,成功拿到access_token了,并且创建了数据表缓存它,还写了一个工具函数获取它,而且当发现它已经过期时,就更新它在数据表中的缓存。


扩展阅读:

原创作者 » 陈帅华
版权声明 » 自由转载-保持署名-非商用-非衍生
发布日期 » 2017年9月5日 周二
更新日期 » 2020年3月8日 周日
上一篇 » 开启微信公众号开发者模式
下一篇 » 验证请求来自微信服务器
:)记录下你此刻的想法~
请选择登录方式,开始记录你的想法。
授权微博登录
授权Github登录
来自笔友的留言