前端通用 Pinia Token 全流程操作指南(常见常用版)

前端通用 Pinia Token 全流程操作指南(常见常用版)

本文梳理 Vue3 官方推荐状态管理库 Pinia 下的 Token 操作逻辑,剥离具体项目细节,聚焦「获取→存储→使用→过期→清除」的核心生命周期,结合 Pinia 「无 mutations、actions 直接异步、模块化更简单」的特性,每个步骤均标注「通用场景+Pinia 通用方案+注意事项」,可直接作为开发速查表。


前置说明:Pinia 与 Vuex 的核心区别(Token 操作相关)

特性VuexPinia
修改状态的方式必须通过 commit 调用 mutationsactions 中可直接修改 state
异步处理actions 处理异步,mutations 同步actions 可直接写 async/await
模块化需开启 namespaced: true 隔离天然模块化,无需额外配置
TypeScript 支持配置复杂原生支持,类型推导友好

一、第一步:登录成功获取并存储 Token

通用场景

用户通过账号密码/验证码等方式登录,后端验证通过后返回 Token,需将 Token 存入 Pinia(全局共享)和本地存储(刷新不丢)。

Pinia 通用方案

  1. 定义 user 模块的 Pinia Store,包含 token 状态和 login 异步 action;
  2. login action 中调用登录接口,提取 Token;
  3. 直接修改 state(无需 commit),同时存入本地存储(推荐 localStorage)。

代码示例

// 1. 定义 Pinia Store(src/stores/user.js)import{ defineStore }from'pinia'import{ loginAPI }from'@/api/user'// 假设已封装好登录接口exportconst useUserStore =defineStore('user',{// state:必须是函数返回对象(避免组件间共享状态)state:()=>({token: localStorage.getItem('token')||''// 初始化时从本地存储读取}),// actions:直接处理异步,可直接修改 stateactions:{asynclogin(loginForm){// 调用登录接口const res =awaitloginAPI(loginForm)// 从接口返回中提取 Token(具体字段看后端文档)const token = res.data.token // 直接修改 state(无需 commit!Pinia 核心优势)this.token = token // 同时存入本地存储 localStorage.setItem('token', token)}}})// 2. 组件中调用(Vue3 组合式 API 示例)<script setup>import{ useUserStore }from'@/stores/user'const userStore =useUserStore()consthandleLogin=async()=>{try{await userStore.login({username:'admin',password:'123456'})alert('登录成功')// 跳转到首页(需结合路由)}catch(err){alert('登录失败:'+(err.response?.data?.msg ||'未知错误'))}}</script>

注意事项

  1. ❌ 不要忘记同时存 Pinia 和本地存储:Pinia 刷新页面会清空,本地存储保证刷新不丢;
  2. ❌ 不要用 Vuex 的思维写 Pinia:无需 commit,直接 this.token = token 即可;
  3. ❌ state 必须是函数返回对象:避免多个组件实例共享同一个 state 对象。

二、第二步:请求接口时自动携带 Token

通用场景

每次发起业务请求时,自动从 Pinia Store 中读取 Token 并添加到请求头。

Pinia 通用方案

  1. 在 Axios/Fetch 封装的请求拦截器中读取 Pinia Store;
  2. 注意:在 Vue 组件外使用 Pinia Store 时,需确保 app.use(pinia) 已执行(通常在 main.js 中先注册 Pinia)。

代码示例

// src/utils/request.js(Axios 封装)import axios from'axios'import{ createPinia }from'pinia'import{ useUserStore }from'@/stores/user'// 初始化 Pinia(组件外使用 Store 必须)const pinia =createPinia()const userStore =useUserStore(pinia)const service = axios.create({baseURL:'/api',timeout:10000})// 请求拦截器:自动带 Token service.interceptors.request.use((config)=>{// 从 Pinia Store 中读取 Tokenconst token = userStore.token if(token){// 添加到请求头(具体字段看后端文档) config.headers['Authorization']=`Bearer ${token}`}return config },(error)=> Promise.reject(error))exportdefault service 

注意事项

  1. ❌ 不要在组件外直接 useUserStore():必须先传入 pinia 实例,否则会报错;
  2. ❌ 不要在每个请求里手动加 Token:用请求拦截器统一处理;
  3. ❌ 不要写错请求头字段名:必须和后端约定一致。

三、第三步:处理 Token 过期

通用场景

Token 过期后,后端返回 401 状态码,需清除 Token 并跳转到登录页。

Pinia 通用方案

  1. 在 Axios/Fetch 封装的响应拦截器中判断 401 状态码;
  2. 调用 Pinia Store 的 logout action 清除 Token;
  3. 强制跳转到登录页。

代码示例

// 1. Pinia Store 补充 logout action(src/stores/user.js)exportconst useUserStore =defineStore('user',{state:()=>({token: localStorage.getItem('token')||''}),actions:{asynclogin(loginForm){/* 登录逻辑 */},// 登出/清除 Token actionlogout(){// 直接修改 statethis.token =''// 清除本地存储 localStorage.removeItem('token')}}})// 2. 响应拦截器补充(src/utils/request.js)import router from'@/router'// 需结合路由 service.interceptors.response.use((response)=> response.data,(error)=>{if(error.response && error.response.status ===401){alert('登录已过期,请重新登录')// 调用 Pinia Store 的 logout action userStore.logout()// 跳转到登录页 router.replace('/login')}else{alert('请求失败:'+(error.response?.data?.msg ||'网络错误'))}return Promise.reject(error)})

注意事项

  1. ❌ 不要只清除 Pinia 不清除本地存储:下次刷新页面旧 Token 又会被读出来;
  2. ❌ 不要忘记跳登录页:Token 过期后用户无法继续操作;
  3. ❌ 跳转登录页建议用 replace:避免用户点击“回退”回到过期页面。

四、第四步:用户主动登出

通用场景

用户点击“退出登录”按钮,需清除所有登录相关数据。

Pinia 通用方案

  1. 给用户二次确认;
  2. 调用 Pinia Store 的 logout action;
  3. 跳转到登录页。

代码示例

<script setup> import { useUserStore } from '@/stores/user' import { useRouter } from 'vue-router' const userStore = useUserStore() const router = useRouter() const handleLogout = () => { if (confirm('确定要退出登录吗?')) { // 调用 Pinia Store 的 logout action userStore.logout() alert('退出成功') router.replace('/login') } } </script> 

注意事项

  1. ❌ 不要省略二次确认:避免用户误触;
  2. ❌ 登出后要彻底清除:包括 Pinia state、本地存储、用户信息(如果有);
  3. ❌ 若后端有登出接口,建议先调用接口再清除前端数据。

五、第五步:路由权限控制(进阶但常用)

通用场景

未登录用户不能访问受保护页面(如首页、个人中心),已登录用户不能访问登录页。

Pinia 通用方案

  1. 在 Vue Router 的 beforeEach 全局前置守卫中读取 Pinia Store;
  2. 定义白名单,判断用户是否登录;
  3. 根据判断结果决定放行或跳转。

代码示例

// src/router/index.jsimport{ createRouter, createWebHistory }from'vue-router'import{ createPinia }from'pinia'import{ useUserStore }from'@/stores/user'const routes =[{path:'/login',component:()=>import('@/views/Login.vue')},{path:'/home',component:()=>import('@/views/Home.vue'),meta:{requiresAuth:true}}]const router =createRouter({history:createWebHistory(), routes })// 初始化 Pinia(路由守卫中使用 Store 必须)const pinia =createPinia()// 全局前置路由守卫 router.beforeEach((to, from, next)=>{const userStore =useUserStore(pinia)const token = userStore.token const whiteList =['/login','/404']if(token){ to.path ==='/login'?next('/home'):next()}else{ whiteList.includes(to.path)?next():next('/login')}})exportdefault router 

注意事项

  1. ❌ 不要在路由守卫中直接 useUserStore():必须先传入 pinia 实例;
  2. ❌ 不要忘记定义白名单:避免无限重定向;
  3. ❌ 前端权限控制仅做拦截:真正的权限校验必须在后端做。

总结:Pinia Token 全流程核心逻辑

  1. 获取+存储:登录接口返回 → Pinia action 直接修改 state + 存本地存储;
  2. 使用:请求拦截器从 Pinia Store 读 Token → 自动加请求头;
  3. 过期:响应拦截器处理 401 → 调用 Pinia logout action → 跳登录页;
  4. 登出:用户确认 → 调用 Pinia logout action → 跳登录页;
  5. 控制:路由守卫从 Pinia Store 读 Token → 白名单判断。

Pinia 专属避坑指南

  1. ❌ 不要用 Vuex 的 commit/mutations 思维:Pinia 直接在 actions 中修改 this.xxx
  2. ❌ 不要在 Vue 组件外直接 useStore():必须先传入 pinia 实例;
  3. ❌ state 不要写成对象:必须是函数返回对象(state: () => ({ token: '' }));
  4. ❌ 不要忘记同时存 Pinia 和本地存储:Pinia 刷新会清空。

Read more

【Spring进阶】Spring IOC实现原理是什么?容器创建和对象创建的时机是什么?

【Spring进阶】Spring IOC实现原理是什么?容器创建和对象创建的时机是什么?

👨‍💻程序员三明治:个人主页 🔥 个人专栏: 《设计模式精解》《重学数据结构》 🤞先做到 再看见! Bean的生命周期 1️⃣** 初始化容器** ApplicationContext ctx =newClassPathXmlApplicationContext("applicationContext.xml"); * ApplicationContext 是 BeanFactory 的子接口; * 它在启动(refresh())时会完成 配置加载 + Bean 注册 + Bean 实例化; * 这是一个预加载容器(启动即创建 Bean)。 ⚠️ 与之相对的 BeanFactory 是延迟加载容器,只有在第一次调用 getBean() 时才会创建对象。 2️⃣** 解析配置并生成 BeanDefinition** Spring 首先会读取配置文件(如 XML 或注解),解析 <bean>

By Ne0inhk
大模型之 Spring AI实战系列(十八):Spring AI Tools 进阶实战——深度集成 RESTful API 联通外部服务

大模型之 Spring AI实战系列(十八):Spring AI Tools 进阶实战——深度集成 RESTful API 联通外部服务

系列篇章💥 No.文章1大模型之Spring AI实战系列(一):基础认知篇 - 开启智能应用开发之旅2大模型之Spring AI实战系列(二):Spring Boot + OpenAI 打造聊天应用全攻略3大模型之Spring AI实战系列(三):Spring Boot + OpenAI 实现聊天应用上下文记忆功能4大模型之Spring AI实战系列(四):Spring Boot + OpenAI 使用OpenAI Embedding实现文本向量化5大模型之Spring AI实战系列(五):Spring Boot + OpenAI 构建带角色设定的智能对话系统6大模型之Spring AI实战系列(六):Spring Boot + OpenAI 利用PromptTemplate构建动态提示词系统7大模型之Spring AI实战系列(七):Spring Boot + OpenAI 构建结构化输出的AI响应系统8大模型之Spring AI实战系列(八):Spring Boot + OpenAI

By Ne0inhk
告别SQL性能焦虑:国产数据库“连接条件下推”的性能魔法

告别SQL性能焦虑:国产数据库“连接条件下推”的性能魔法

文章目录 * 一、 为什么你的复杂SQL会“爆内存”?—— 深度剖析现代SQL的性能陷阱 * 二、 金仓的解决方案:“智能下推”策略 —— 先判定,再评估 * 三、 效果:数字会说话,性能提升超千倍 * 四、 技术深度剖析:连接条件下推的实现原理 * **未来展望** 你是否遇到过这样的场景:一个看似逻辑清晰的复杂SQL,在测试环境运行飞快,一到生产环境就“卡死”,甚至直接爆出内存溢出?排查时发现,执行计划中生成了一个巨大的中间结果集,导致后续的排序、连接操作全部陷入性能泥潭。如果这是你日常工作中的常态,那么,是时候认识一项能够改变游戏规则的技术——金仓数据库(KingbaseES)的「基于代价的连接条件下推」。它不仅仅是一项简单的优化技巧,更是应对复杂业务查询的“性能终结者”,将数据库优化器的智能化提升到了一个新的高度。 一、 为什么你的复杂SQL会“爆内存”?—— 深度剖析现代SQL的性能陷阱 在金融、政务、电信等企业级核心系统中,业务逻辑往往极其复杂。为了代码的可读性和维护性,开发人员倾向于使用多层嵌套子查询、

By Ne0inhk