微信开发排坑:access_token 的缓存与刷新策略
Words: 1002Read Time: 3 minLast edited: 2026-8-4
access_token 的两条硬规则
做公众号开发,access_token 是绕不开的第一课。微信对它就两条硬规则,但每条都能让人掉坑:
- 有效期 7200 秒(2 小时),过期作废
- 获取接口有每日调用次数上限,而且重复获取会让旧 token 很快失效,新旧之间只有很短的共存窗口
为什么必须集中缓存
我第一次接公众号时图省事,每次调微信接口前都现取一次 token。测试环境屁事没有,上线半天就收到报警:获取 token 的接口当天调用次数被打满,后续请求全部失败。
更要命的是并发调用时互相「踢 token」:A 取了一个 token 正在用,B 又取了一个新的,A 手里那个很快就失效,请求报
40001 invalid credential。所以结论只有一个:access_token 必须全局只维护一份,集中缓存、提前刷新,任何业务代码都不允许直接调获取接口。MemoryCache + 提前刷新的实现
单体应用用内存缓存就够了,核心代码:
几个细节值得说一下:
- 提前 5 分钟过期:缓存时间设成
expires_in - 300。不留缓冲的话,可能出现缓存里 token 还差几秒过期、微信那边已经作废的情况,请求恰好卡在边界上就报错。
- 信号量加双重检查:缓存过期瞬间会有多个请求同时来取,没有锁就是一窝蜂去打微信接口,又变成互相踢 token。
- 别忘了判断 errcode:微信接口即使失败也返回 HTTP 200,错误信息在响应体里。不判断就把错误消息当 token 缓存起来了——别问我怎么知道的。
这个服务注册成单例,配合
IHttpClientFactory 使用即可。多实例部署的坑
上面这套在单实例下很稳。后来我把服务部署成两台做负载均衡,问题又回来了:两台机器各自维护各自的内存缓存,各自到点刷新,又回到互相踢 token 的老路上,错误日志里
40001 隔三差五冒一个。解决思路有两个:
- 换成分布式缓存:把 token 存 Redis,所有实例共享一份,刷新时加分布式锁,保证同一时刻只有一个实例在刷新。
- 刷新收敛到一个点:单独跑一个后台任务定时刷新 token 写进 Redis,应用实例只读不写,连锁都省了。
我最后选了方案一,用 Redis 的
SET NX 当分布式锁,对现有代码改动最小。另外微信后来推出了 stable_token 接口,支持强制刷新模式、token 有效期内重复获取不会互相失效,对多实例场景友好不少,新接手的项目可以优先考虑。这类「看似简单的第三方凭证」,单机、并发、多实例三种场景完全是三个问题,设计时最好一步到位按最复杂的想。
Loading...