微信小程序access_token
发布时间:10-23来源:微信小程序工具|微信小程序开发|微信小程序制作平台-龙图应用【XcxIP.com】
搞微信小程序开发的人,几乎都跟accesstoken打过交道。这玩意儿说简单也简单,就是一个字符串,但说复杂也真复杂,多少人半夜被它折腾醒,就因为token过期了,接口突然返回401。你翻文档,文档写得明明白白,有效期7200秒,两小时。可实际用起来,坑一个接一个,今天我就把这些坑一个个给你扒开,聊点文档里没写明白的事。

先说说这个token到底是个啥。微信小程序的accesstoken,是全局唯一调用凭证,你调任何涉及用户数据、支付、消息推送的接口,都得带着它。它不像你登录时拿到的那个sessionkey,那是用户维度的,accesstoken是应用维度的,说白了,就是你整个小程序身份的象征。你代码里所有会打到api.weixin的请求,header里都得塞上它,不然微信服务器直接翻脸不认人。
但问题就出在这个“全局唯一”上。微信规定,同一时间只能有一个有效的accesstoken,你新获取一个,旧的立马失效。这规则听着不复杂,可一旦你的服务端不止一台机器,或者你用了微服务架构,就麻烦了。我之前见过一个项目,开发环境、测试环境、生产环境共用同一个AppID,结果前端调试的时候拉一次token,后端跑定时任务的时候也拉一次,两边互相踩,接口时好时坏,查了半天才发现是token互相顶掉了。
所以第一原则:千万不能每次请求都去获取新token,必须做本地缓存。这缓存怎么做,就有讲究了。最简单的,存内存里,一个静态变量,配个过期时间判断。但内存缓存有个致命伤,进程重启就没了,而且多实例部署时各存各的,照样冲突。稍微好点的,存Redis,设置key过期时间,比如7000秒,比官方7200秒稍微提前一点过期,留出余量。这样多台机器共享同一个token,谁用谁去取,取不到就刷新,基本能规避冲突问题。
可你以为存了就完事了?还有个并发问题。假设你的服务突然被刷了,十个请求同时发现Redis里的token过期了,然后同时去微信那边拉新token。微信那边可不管你并发不并发,它只认一次请求,先到的几个请求拿到的是旧token,后到的把前面的顶掉了,结果先拿到token的那几个请求去调接口,发现又被顶了,又报401。这就是经典的缓存击穿加并发刷新问题。
解法也不难,加个分布式锁。Redis里设一个锁key,谁抢到锁谁去刷新token,其他请求等着,等锁释放了再去读新的token。或者更简单粗暴,用单例模式加双检锁,Java里synchronized,Python里threading.Lock,Node里用async-mutex,都能解决。但要注意,锁的粒度一定要锁在“刷新token”这个动作上,而不是锁整个业务逻辑,不然性能会拖垮。
再说说token过期时间。官方说7200秒,但实际你提前多久刷新合适?我见过有人设6000秒,有人设7000秒,还有人干脆就不关心,等报错了再刷新。这里有个坑,微信那边对accesstoken的获取频率是有限制的,每天刷新次数不能超过2000次,而且如果短时间内频繁刷新,会触发微信的风控,直接给你禁掉获取接口。所以刷新策略一定要保守,我一般建议设6500秒,留出10分钟余量,够应付网络抖动和时间误差了。
还有个容易被忽略的点,accesstoken的有效期是从你获取那一刻开始算的,不是从你缓存那一刻开始的。如果你获取用了100毫秒,网络传输又耗了100毫秒,那实际可用时间就少了200毫秒。别小看这几百毫秒,在高峰期,你的定时任务刚好卡在一刻去调接口,就可能因为这几百毫秒的误差直接失败。所以缓存过期时间建议比实际有效时间再提前个1-2分钟。
接下来聊聊怎么获取token。接口地址固定,就是GET请求,参数传granttype=clientcredential,还有appid和secret。这接口本身不复杂,但有个细节很多人不注意,返回的JSON里除了accesstoken,还有个expiresin字段,单位是秒。别偷懒硬编码7200,要动态读这个值去做缓存判断,万一哪天微信那边调整了有效期,你的代码还能自适应。
再讲讲token失效的常见原因。除了被新token顶掉,还有一种情况是换了AppSecret。有时候你改了小程序后台的密钥,忘了更新服务端配置,那旧的token就废了。还有一种,小程序被封禁或者迁移了主体,token也会失效。这些情况比较极端,但真遇到了,你会发现自己写的那些“token失效自动刷新”的逻辑全都不管用,因为根本不是过期问题,是身份问题。
那怎么排查token问题?我建议你在服务端加个日志,每次获取token、刷新token、以及调用业务接口时token的校验结果,都记录下来。一旦出问题,先看日志里token的获取时间和使用时间,判断是不是过期顶替。再配合微信后台的“接口调用频率”统计,能快速定位是并发冲突还是被风控了。
说个实战技巧。如果你用的是微信云开发,那其实不用自己管token,云函数里调用微信接口时,云开发会自动帮你注入accesstoken。但如果你还是传统服务器架构,那就得自己扛。我的建议是,把token的获取和刷新封装成一个独立服务,对外只暴露一个getToken函数,内部处理缓存、锁、过期刷新,业务方只管调,不用关心实现细节。这样即使以后微信调整规则,你也只需要改这一个地方。
accesstoken这东西,说白了就是一把钥匙,但钥匙保管不好,门照样开不了。很多人觉得它简单,结果上线第一天就被它坑了。记住三件事:缓存必须做,锁必须加,过期时间必须留余量。做到这三点,你基本就能跟accesstoken和平共处了。下次如果你半夜又被401吵醒,先别急着骂微信,翻翻你的缓存策略和锁实现,大概率问题出在自己代码里。
