前端通用 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

如何设计一套 Java 项目的 Skill 体系

如何设计一套 Java 项目的 Skill 体系

关键词:Skill 体系 | 架构设计 | 模块化 | 可组合 | 工程化思维 一、从单个 Skill 到 Skill 体系:质变的开始 前面两篇文章,我们分别讲了: * Service Skill:自动生成业务层代码 * Controller Skill:自动生成接口层代码 但如果只是零散的 Skill,那还只是"工具集"。 真正的威力在于: 把多个 Skill 组织成体系,形成协同作战的能力矩阵 这就像: * 单个技能 = 单兵作战 * Skill 体系 = 特种部队 从"点"到"面",从"工具&

By Ne0inhk
手把手带你吃透Java中的WebSocket,纯干货不废话!

手把手带你吃透Java中的WebSocket,纯干货不废话!

手把手带你吃透Java中的WebSocket,纯干货不废话! 一、从 “小麻烦” 引出 WebSocket 在互联网的世界里,HTTP 协议就像是一个勤劳的 “快递员”,一直勤勤恳恳地为客户端和服务器传递着信息。多年来,HTTP 协议凭借着简单、灵活的特性,成为了 Web 通信的基石,像我们日常上网浏览网页、提交表单等操作,背后都离不开 HTTP 协议的支持。它采用请求 - 响应的模式,客户端发起请求,服务器返回响应,这种模式就好比你在网上购物,下单(发送请求)后等待商家发货(返回响应),简单直接,在大多数情况下都能很好地满足我们的需求。 不过,时代在发展,互联网应用也越来越丰富多样。就像你现在不满足于只是逛逛静态网页,还想和朋友来一场畅快淋漓的在线聊天,或者实时查看股票行情的变化。这时候,HTTP 协议这个 “老快递员” 就有点力不从心了。因为 HTTP 协议是单向通信的,

By Ne0inhk
JavaScript DOM 核心操作:从内容到节点的实战指南

JavaScript DOM 核心操作:从内容到节点的实战指南

DOM(文档对象模型)是前端开发中操作页面结构、内容和样式的核心,本文聚焦 DOM 中元素内容、属性、样式的读写修改,以及节点的增删改,结合实战示例讲解核心用法与最佳实践。 一、操作元素内容 元素内容操作分为纯文本处理和带 HTML 结构的处理,核心使用 innerText 和 innerHTML 两个属性,二者特性对比如下: 方法识别 HTML 标签保留换行 / 空格标准性适用场景innerText❌❌非标准(IE)仅读取 / 修改纯文本innerHTML✅✅W3C 标准读取 / 修改带 HTML 结构的内容 1. innerText:纯文本操作 仅处理文本内容,会忽略 HTML 标签和源码中的换行 / 空格,适合简单文本读写。 // 读操作:获取元素纯文本内容 var text = element.innerText;

By Ne0inhk
【JAVA 进阶】Spring Boot自动配置详解

【JAVA 进阶】Spring Boot自动配置详解

文章目录 * 一、Spring Boot 与自动配置初相识 * 1.1 Spring Boot 简介 * 1.2 自动配置的概念 * 1.3 自动配置的重要性 * 二、Spring Boot 自动配置核心原理 * 2.1 核心注解 @EnableAutoConfiguration * 2.2 AutoConfigurationImportSelector * 2.3 Spring Factories 机制 * 三、自动配置实战演练 * 3.1 创建 Spring Boot 项目 * 3.2 配置文件详解 * 3.3 自定义自动配置 * 四、自动配置高级应用与问题解决 * 4.1

By Ne0inhk