主题
高级项目实践面试题
Vue 项目如何设计登录会话、Token 刷新和多标签页同步?
考察认证状态、会话生命周期、并发刷新和浏览器安全边界。
面试官想考什么
- 能否先明确问题边界?
考察认证状态、会话生命周期、并发刷新和浏览器安全边界。 - 能否讲清核心链路和状态变化?
重点考察:请求发现 401 后进入单飞刷新队列,刷新成功后重放可重试请求,失败则清理会话并跳转登录;多标签页通过 BroadcastChannel 或 storage 事件同步退出。 - 能否说明取舍,而不是只给单一方案?
重点考察:HttpOnly Cookie 能降低脚本读取凭证的风险,Token 放内存能减少持久化暴露但刷新后会丢失;选择要结合后端会话和 CSRF 防护。 - 能否把方案落到项目治理?
重点考察:不把 access token 写入日志和 URL,刷新接口设置超时与幂等策略,退出时撤销服务端会话,并为过期、无权限和网络失败分别设计 UI。
一句话回答
text
认证要区分身份状态、凭证存储、请求注入、刷新并发和退出同步;前端只能改善体验,真正的权限判断必须由服务端完成。面试回答详解
这道题的关键不是背一个 Vue API,而是把业务目标、状态边界、运行时链路和上线后的失败恢复放在同一个设计里。
1. 先拆问题和边界
考察认证状态、会话生命周期、并发刷新和浏览器安全边界。 HttpOnly Cookie 能降低脚本读取凭证的风险,Token 放内存能减少持久化暴露但刷新后会丢失;选择要结合后端会话和 CSRF 防护。
2. 核心机制
请求发现 401 后进入单飞刷新队列,刷新成功后重放可重试请求,失败则清理会话并跳转登录;多标签页通过 BroadcastChannel 或 storage 事件同步退出。
text
需求与约束 -> 状态/模块建模 -> Vue 组件与基础设施协作 -> 失败恢复 -> 指标验证3. 工程落地
不把 access token 写入日志和 URL,刷新接口设置超时与幂等策略,退出时撤销服务端会话,并为过期、无权限和网络失败分别设计 UI。
- 契约:明确输入、输出、错误模型和生命周期,避免组件依赖隐式全局状态。
- 异常:为网络失败、权限变化、取消、重复操作和卸载分别设计行为。
- 验证:通过类型、单元/组件测试、E2E、性能指标和线上日志验证,而不是只看本地能否运行。
- 演进:把稳定能力沉淀为模块 API,把易变业务留在 feature 内,保留迁移和回滚路径。
4. 方案取舍
HttpOnly Cookie 能降低脚本读取凭证的风险,Token 放内存能减少持久化暴露但刷新后会丢失;选择要结合后端会话和 CSRF 防护。
不要把架构复杂度本身当成成熟度。高级答案应说明何时采用简单实现,何时值得引入抽象,以及抽象带来的调试、性能和团队认知成本。
5. 生产风险
不把 access token 写入日志和 URL,刷新接口设置超时与幂等策略,退出时撤销服务端会话,并为过期、无权限和网络失败分别设计 UI。 还要补充数据隐私、权限校验、资源释放、兼容性、灰度发布和可观测性。前端可以改善用户体验,但不能替代服务端授权、数据一致性和安全校验。
可直接背诵的 30 秒回答
text
我会先把问题拆成目标、状态、模块边界和失败场景。认证要区分身份状态、凭证存储、请求注入、刷新并发和退出同步;前端只能改善体验,真正的权限判断必须由服务端完成。 实现上我会让 Vue 组件负责展示和交互,把请求、领域规则和基础设施隔离,通过明确契约连接;同时覆盖 loading、error、empty、取消、重复操作和卸载。最后用类型、测试、性能指标和线上监控验证方案,而不是只证明功能能跑。扩展知识
一个通用项目设计框架
text
业务目标 -> 领域边界 -> 状态所有权 -> 依赖方向 -> 异常恢复 -> 测试与观测 -> 灰度与回滚常见误区
- 把前端隐藏、路由拦截或 TypeScript 类型当成真正的安全边界。
- 只讲正常流程,不讲刷新、并发、取消、卸载、断网和版本不一致。
- 只看局部代码能否运行,不看模块耦合、性能、测试和发布成本。
- 引入抽象后没有公共契约、迁移路径和删除旧实现的计划。
面试官追问链
追问一:多个请求同时 401 如何处理?
- 考察点:确认候选人是否能把方案落到生产边界。
- 回答方向:结合数据规模、失败恢复、可观测性和团队维护成本回答,不要只给 API 名称。
追问二:刷新失败时如何避免死循环?
- 考察点:确认候选人是否能把方案落到生产边界。
- 回答方向:结合数据规模、失败恢复、可观测性和团队维护成本回答,不要只给 API 名称。
追问三:为什么不能只靠前端隐藏按钮做权限?
- 考察点:确认候选人是否能把方案落到生产边界。
- 回答方向:结合数据规模、失败恢复、可观测性和团队维护成本回答,不要只给 API 名称。