
接口调用出问题一半出在鉴权。Token 怎么拿、缓存在哪、过期怎么刷、多账号怎么隔离这几件事没理顺后面每个接口调用都要被 401 折腾一遍。这篇把鉴权这一段单独讲透再接上正常调用。一、拿 TokenappId 换 Token 的两步第一步用 appId 和 secret 换 Token第二步拿 Token 调业务接口。Token 不是永久有效的返回里一般带一个有效期字段写法见Eyun 开发文档。要点是别每次调用都去换 Token——换 Token 本身也是接口调用高频换会触发限制。拿到就缓存用到快过期再换。二、缓存与刷新别等到 401 才反应缓存 Token 要连过期时间一起存。推荐在过期前的一个窗口主动刷新而不是等接口返回 401 再处理——401 意味着这次调用已经失败了用户那一侧已经受影响。并发场景要注意多个线程同时发现 Token 快过期会一起去刷新。用锁或单飞single-flight保证只有一个在刷其他等结果。三、多账号隔离一套配置一个命名空间多账号时不能共用一个 Token。每个账号有自己的 appId 和 Token缓存也要按账号分开存key 用账号 ID 做前缀取的时候按账号取。这一段踩过坑早期共用一个缓存 key结果 A 账号的 Token 被 B 账号覆盖两边调用全挂。鉴权环节对照环节做法要点常见坑获取appIdsecret 换 Token不重复换每次调用都换缓存带过期时间存储提前主动刷新等 401 才反应并发单飞保证唯一刷新其他等待结果并发重复刷新多账号按账号分命名空间独立 Token缓存 key 撞车鉴权与调用实现import threading import time class TokenVault: def __init__(self, api, app_id, secret): self.api api self.app_id app_id self.secret secret self.tokens {} # account - (token, expire_at) self.locks {} def token_of(self, account): token, expire self.tokens.get(account, (None, 0)) if token and time.time() expire - 60: # 提前60秒才算可用 return token lock self.locks.setdefault(account, threading.Lock()) with lock: token, expire self.tokens.get(account, (None, 0)) if token and time.time() expire - 60: return token # 双检别人已刷好 resp self.api.post(/auth/token, { app_id: self.app_id, secret: self.secret, account: account, }) token resp[token] expire time.time() resp[expires_in] self.tokens[account] (token, expire) # 按账号分开存 return token def call(self, account, path, payload): # 统一出口自动带 Token401 自动刷新重试一次 for _ in range(2): token self.token_of(account) r self.api.post(path, payload, headers{Authorization: token}) if r.status_code 401: self.tokens.pop(account, None) # 清掉旧 Token continue return r.json() return {code: -1, msg: 鉴权失败}落地建议Token 拿到就缓存别每次调用都换。过期前主动刷新别等 401 影响用户请求。并发刷新用单飞避免多线程重复换。多账号按账号分命名空间存 Token防止缓存互相覆盖。所有调用走统一出口401 自动重试一次。微信侧的鉴权与业务接口由 Eyun 这类个人微信API平台 提供Token 管理与调用封装在自建服务实现具体字段以Eyun 平台为准。