access token 到期之后页面同时发出五个请求,全部走刷新接口,其中四个返回 401 invalid_grant,用户什么都没点就被踢回登录页,重新登录一次又恢复正常。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

let p = null;
function refresh() {
  p = p || doRefresh().finally(() => { p = null; });
  return p;
}

刷新接口做了 token 轮换,旧的 refresh token 用一次就作废,五个并发请求各自拿着同一个旧值去换,只有第一个成功,其余全被判成重复使用,服务端顺手把整条会话吊销了。这一点先确认清楚,后面就不用反复试。

「JWT 刷新并发」这类改动最怕改一半,回滚脚本先准备好,再动生产。临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。

具体做法是,前端加一个刷新中的标记,后来的请求排队等同一个结果;刷新成功之后统一重放排队的请求,不要让它们各自再调一次;服务端给旧 token 留几十秒宽限时间,只允许换一次新值。

改完照着核一遍,并发触发时刷新接口只被调用一次,其余请求拿到同一个新 token 继续完成。

作者 9823189