Chrome 扩展请求 Google Ads 接口,我把 OAuth 令牌有效期卡在 55 分钟

给伊斯坦布尔一家做家居用品的客户维护一个内部小工具:Chrome 扩展(Manifest V3,Chrome 120 上下)定时拉 Google Ads 的广告系列消耗,写进他们自己的看板。数据量不大,一天几十个广告系列、几千行消耗记录,但要求准点——他们每天早上九点看前一天的数。原来的写法是扩展里直接用 chrome.identity.getAuthToken 拿令牌,拉一次接口,报 401 就重新拿一次。看起来能跑,实际每天九点前后总有两三次空数据,日志里是 invalid_grant。

先把取令牌的逻辑从扩展的 service worker 里挪出来,改成显式管理过期时间:

let cached = { token: null, exp: 0 };
async function getToken() {
  const now = Date.now();
  if (cached.token && now < cached.exp) return cached.token;
  const t = await chrome.identity.getAuthToken({ interactive: false });
  // Chrome 不回调 expires_in,按 3600s 保守取 3300s
  cached = { token: t, exp: now + 55 * 60 * 1000 };
  return t;
}

再在请求侧加一层:401 时先 chrome.identity.removeCachedAuthToken({ token }) 再重取,避免拿到同一个已失效的令牌反复打接口。同时把定时拉到 chrome.alarms 里,周期 30 分钟,而不是靠页面打开触发。

选 55 分钟而不是 60,是权衡后的结果。Google 的 access token 名义有效期 3600 秒,但扩展拿到的令牌在 service worker 被回收、机器休眠、系统时间跳变时,剩余寿命并不可控;留 5 分钟余量,代价是每小时多一次换令牌请求,几乎可以忽略。把令牌存在 service worker 的内存里而不是 chrome.storage,则是因为 MV3 的 worker 随时可能被停,写进存储反而会让“看起来没过期、实际已失效”的令牌存活更久——我宁可它跟着 worker 一起消失。

失效的边界比想象中多。第一,用户改 Google 账号密码或在账号安全页撤销授权,invalid_grant 会直接回来,这时任何缓存策略都救不了,只能走一次 interactive: true 让用户重新点授权,我的做法是捕获这个错误码后弹一个 badge 提示,而不是静默重试。第二,多台机器同一账号并发拉数据时,removeCachedAuthToken 只清当前这台,别的机器不受影响,但如果客户在别的设备上点了撤销,这边要等下一次 401 才发现,最多滞后 30 分钟。第三,系统时间被手动调快超过 5 分钟,本地 exp 判断会提前失效,表现为“令牌明明刚拿就重取”,这个我在一台测试机上复现过一次,最后是加了服务端返回的 Date 头做粗略校正才压住。

现在每天早上九点的数据基本齐了,但 401 重试那条路径我只在单机上验证过,没在客户那种多人共用一个 Google 账号、又各自开扩展的场景下跑过。你们在多设备共享授权时,是每台机器各自维护令牌,还是集中到一个中间层去换?

0
赞同度 100% · 0 条评论 · 6 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。