前端无法真正实现 Session,所谓“无感刷新 Access-Token”是通过拦截 401 响应、用 Refresh-Token 主动/被动刷新 Access-Token,并避免并发刷新与 XSS 风险,依赖后端接口与 Cookie 策略协同完成。

前端无法真正“实现” Session,因为 Session 是服务端机制。所谓“无感刷新 Access-Token”,本质是前端配合后端,在 Token 过期前自动发起刷新请求,避免用户感知登录中断。关键不在前端“维护 Session”,而在合理设计 Token 刷新策略与请求拦截逻辑。
理解 Access-Token 与 Refresh-Token 的分工
Access-Token 有效期短(如 15–30 分钟),用于每次 API 请求鉴权;Refresh-Token 有效期长(如 7 天),仅用于换取新 Access-Token,且需安全存储(HttpOnly Cookie 最佳,若必须前端存则用内存变量 + 防 XSS 保护)。
- Access-Token 不应存 localStorage —— 易被 XSS 窃取
- Refresh-Token 若存前端,绝不能放 localStorage/sessionStorage
- 推荐方案:后端通过 HttpOnly + Secure + SameSite=Strict 的 Cookie 返回 Refresh-Token,前端完全不触碰其值
用请求拦截器捕获 401 并触发刷新
所有业务请求统一走 Axios 或自定义 fetch 封装。当响应返回 401(Unauthorized)时,不是直接跳登录页,而是尝试用 Refresh-Token 换新 Access-Token。
- 拦截 401 响应,标记该请求为“待重试”
- 发起 /auth/refresh 接口(自动携带 Refresh-Token Cookie)
- 刷新成功后,更新内存中的 Access-Token,并重放原始请求
- 刷新失败(如 403 或网络错误),才清空状态、跳转登录页
避免并发刷新导致多次请求
多个请求几乎同时 401 时,只允许一个刷新请求执行,其余等待其完成后再重发——否则可能触发刷新 Token 失效(部分后端设计为“一换即废”)。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
- 用 Promise 缓存刷新请求:首次 401 触发刷新,后续 401 直接 await 同一个 Promise
- 刷新完成后,清空缓存,确保下次 401 重新发起
- 示例:let refreshPromise = null;if (!refreshPromise) { refreshPromise = api.refresh() };await refreshPromise
主动预刷新防临界过期
仅靠 401 被动刷新会有体验断层(比如提交表单瞬间 Token 过期)。可在 Token 即将过期前(如剩余 60 秒)主动刷新。
- 解析 Access-Token 的 exp 字段(JWT 可 base64 解码 payload 获取)
- 启动定时器:在 exp 前 60 秒调用刷新接口
- 刷新成功后重设计时器;失败则保留原 Token,等真实 401 再兜底处理
- 注意:定时器需在页面可见时运行,切页或休眠时暂停,避免无效请求
不复杂但容易忽略细节:Token 刷新不是前端单方面能搞定的事,它高度依赖后端接口设计、Cookie 策略和错误码规范。前端要做的,是稳住请求链路、管好 Token 生命周期、守住安全边界。

















