1. まずプロジェクトに aiXos と pinia をダウンロードします
npm i pinia --save npm install axios --save
2. axios リクエストをカプセル化します-----
ダウンロードjs-cookie
npm i JS-cookie -s //引入aixos import type { AxiosRequestConfig, AxiosResponse } from "axios"; import axios from 'axios'; import { ElMessage } from 'element-plus'; import { useUserInfoStore } from '@/stores/modules/UserInfo' import router from '@/router'; import qs from 'qs'; import Cookie from "js-cookie"; let baseURL = ""; // console.log(process.env.NODE_ENV);//判断环境 if (process.env.NODE_ENV === 'development') { baseURL = '/m.api'//后台请求接口地址 } else { baseURL = 'http://xxxx.cn:8080';//这里是项目上线后的地址 } declare interface TypeResponse extends AxiosResponse { /** * 错误号,200表示成功,10006令牌过期 */ errno: number, /** * 返回的信息 */ errmsg: string } //创建axios实例 const instance = axios.create({ baseURL, // 接口地址 timeout: 3000, headers: { "Content-Type": 'application/x-www-form-urlencoded' } }); //添加拦截器 instance.interceptors.request.use((config) => { // 在发送请求之前做些什么--给请求头添加令牌token (config as any).headers['AdminToken'] = Cookie.get('token')//从cookie中拿token值, //这里是使用了js-cookie插件。 // console.log(config, "请求拦截器") return config }, reeor => { // 对请求错误做些什么 return Promise.reject(reeor); }); // 需要无痛刷新的操作页面 const METHOD_TYPE = ["_mt=edit", "_mt=create", "_mt=delete"] // //响应拦截器 instance.interceptors.response.use(async (response: AxiosResponse) => { // 对响应数据做点什么 let data = response.data; let { errno, errmsg } = data; console.log(response, "响应拦截器"); let path = router.currentRoute.value.fullPath;//当前路由路径 if (10006 === errno) { const configData = response.config.data || '' // 判断请求类型是否需要无痛刷新,index !== -1则需要无痛刷新 let index = METHOD_TYPE.findIndex(item => configData.includes(item)) if (-1 === index) {//需要重新登入获取令牌 router.replace({ path: "/login", query: { back: path } })//登入后需要跳回的地址 return } else {//需要无痛刷新令牌 const store = useUserInfoStore(); const { username, password } = store.LoginInfo//在状态管理里面定义一个loginInfo // 1.重新获取令牌 let loginData = { _gp: 'admin', _mt: 'login', username, password }; const { errno, errmsg, data } = await post(loginData)//这里是通过async 将异步序列化改为同步 if (200 == errno) { Cookie.set('token', data)//保存令牌 } else { router.replace({ path: "/login", query: { back: path } })//登入后需要跳回的地址 return Promise.reject({ errno, errmsg, data }) } return instance.request(response.config) } // ElMessage.error(errmsg);//错误信息 } return data; }, reeor => { console.log(reeor); return Promise.reject(reeor); }) function get(params?: object): Promise<TypeResponse> { return instance.get('', { params }); }; function post(data: object, params?: object): Promise<TypeResponse> { return instance.post('', qs.stringify(data), { params }); }; //暴露实列 export { post, get, }
3.qs.stringify(data) は、要求されたデータをフォーム形式に変換するためのものです。必要ない場合は、直接削除してください。
4.再度ログインしてジャンプします。 ルーティングを設定する必要があります。必要がない場合は、
5 を削除できます。状態管理 -- データ
永続化ツールのダウンロード
npm install pinia-plugin-persistedstate --s
main.js で永続性を構成
//引入数据持久化插件 import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'; const pinia = createPinia() pinia.use(piniaPluginPersistedstate); app.use(pinia)
import { defineStore } from 'pinia' export const useUserInfoStore = defineStore('UserInfo', { state:() => ({ LoginInfo:{ username:'', password:'' } }), persist:true;//状态存储持久化 })
6. ログイン ページ -- ストレージ フォーム データ、つまりユーザー名とパスワード
npm i lodash --s import Cookies from 'js-cookie';//引入cookie import * as _ from 'lodash';//防抖节流插件 import {post} from '@/util'; import {useUserInfoStore} from '@/stores/modules/UserInfo' ;//用户信息 import { useRouter,useRoute } from 'vue-router' ;//引入路由 //这里是表单输入的数据 const ruleForm = reactive({ password: '123456', username: 'admin' }); //请求接口数据 let data = { _gp: "admin", _mt: 'login', ...ruleForm }; let LoginInfo = useUserInfoStore().LoginInfo;//状态管理定义的数据 async function init() { await post(data).then((res:any) => { let { data: token, errno, errmsg } = res if (200 === errno) { let time = new Date() //设置过期时间 time.setTime(time.getTime() + 1000 * 60 * 30) Cookies.set('token', token, { expires: time }); Object.assign(LoginInfo,ruleForm) if (route.query.back) { //如果存在参数 let paths = route.query.back+''//拼接字符串 console.log(paths); if (paths=='/') { //因为我的home是'/',所有需要判断 router.replace('/Surface')//跳转至主页 return }else{ router.replace(paths)//则跳转至进入登录页前的路由 } } else { router.replace('/Surface')//否则跳转至首页 } } else { ElMessage.error(errmsg) } }).catch((err:any) => { ElMessage.error('登录异常!') }) let info = {//用户信息请求信息接口数据 _gp: "admin", _mt: 'info', } //下面这个函数是请求用户信息的,不需要可以不写 await post(info).then((res:any) => { let {data} = res console.log(data); infos(data) }).catch((err:any)=>{ ElMessage.error('登录异常!') }) } //防抖节流 const fangdou = _.debounce(init, 1500, { leading: true, // 延长开始后调用 trailing: false // 延长结束前调用 }) //移除组件时,取消防抖 onUnmounted(() => { fangdou.cancel() })
7.main.js ルーティングガードの設定
import Cookie from 'js-cookie' import router from './router'//引入路由 //路由守卫 router.beforeEach(async (to, from ) => { let tokent:string|undefined = Cookie.get('token') if (!tokent && to.path == '/login') { return true } // 没有登录,强制跳转登录页 if (!tokent && to.path !== '/login') { router.replace({path:'/login',query:{back:to.path}}); } // 防止重复登录 if (tokent && to.path === '/login') { return { path: from.path ? from.path : '/Surface' } } return true })
以上です
無痛リフレッシュの原理: トークンの有効期限が切れると、応答インターセプターは判断を通じてログイン要求を再作成します。
ユーザーのアカウントとパスワードを保存するために、状態管理状態で loginInfo オブジェクトを定義します。
//在状态管理文件中 import { defineStore } from 'pinia' import Cookies from "js.cookie" import {post} from '@/http' import router from '@/router'; import { ElMessage } from 'element-plus'; export const useUserStore = defineStore({ id: "userStore", persist: { paths:['user'] },//持久化 state: () => ({ loginInfo:{ username:'', password:'' } }), getters: {}, actions: { setUser(user:UserInfo) { this.user = user; }, loginOut(){ const data ={ _gp:"admin", _mt:"logout" } post({},data).then((res:any)=>{ let {errmsg,errno} = res if(200==errno){ localStorage.removeItem("userStore") Cookies.remove("token") router.replace('/login') ElMessage.success(errmsg); }else{ ElMessage.error(errmsg); } }).catch(res=>{ console.log(res,"退出登入失败"); }) } } })
//在登入页面文件中 const data = { ...ruleForm, _gp: "admin", _mt: "login" }//转换成字符串 post({}, data).then(res => { let { data: token, errmsg, errno } = res as any;//获取登录状态 if (200 == errno) {//登录成功的判断 ElMessage.success("登录成功!")//消息提示登录成功 let now = new Date();//获取当前时间 now.setTime(now.getTime() + 1000 * 60 * 30);//转成时间类型 Cookies.set("token", res.data, { expires: now })//获取token存到cookie Object.assign(store.loginInfo, ruleForm)//将账号密码存储到状态管理 return Promise.resolve(token) } else { ElMessage.error(errmsg);//登入失败 return Promise.reject(errmsg) } })
#5トークンの有効期限が切れます。インターフェイス リクエスト データを取得し、定義された配列内で検索して、リクエスト タイプに痛みのない更新が必要かどうかを判断します。
6.index===-1 は、配列内に見つからないことを意味します。更新するのは面倒なので、ログイン ページに直接ジャンプして
7.index にログインしてください。 ==-1 は、痛みのない更新が必要であることを意味し、ステータス管理に保存されているユーザー アカウントとパスワードを分解し、トークンを再取得するためのログイン インターフェイス リクエストを作成し、ログイン ページに入らずにログイン リクエストを作成します。痛みのないリフレッシュ
//在封装的http文件中 import axios, { type AxiosResponse } from 'axios'; import qs from 'qs' import Cookies from "js.cookie" import router from '@/router'; import { ElMessage } from 'element-plus'; import { useUserStore } from '@/stores/admin'; declare interface TypeResponse extends AxiosResponse { url(url: any): unknown; [x: string]: any; /** * 错误号,200表示成功,10006令牌过期 */ errno: number, /** * 失败返回的消息 */ error: string, /** * 成功后返回的消息 */ errmsg: string } let baseURL = '' if (process.env.NODE_ENV === "development") { baseURL = '/m.api' } else { baseURL = "http://zxwyit.cn:8080/m.api"//上线后的路径 } const instance = axios.create({//创建实例 baseURL, headers: { "content-type": "application/x-www-form-urlencoded" } }) // 请求拦截器 instance.interceptors.request.use(function (config) { if (config.headers) { config.headers['AdminToken'] = Cookies.get("token") + '' } return config }, function (error) { console.error('请求错误', error) return Promise.reject(error) } ) // 无痛刷新的原理:当token过期后,在响应拦截器通过判断重新进行登入请求 // 实现过程: // 1.在状态管理state中定义一个loginInfo对象用于存储用户的账号和密码 // 2.登入页面中,在登入请求成功后将用户的账号和密码存储在状态管理 // 3.在http中,先定义一个数组变量,该数组存放需要无痛刷新的操作如:删除、添加、编辑 // 4.在响应拦截器中,判断10006是否等于errno,如果相等说明令牌过期了,否则没过期 // 5.令牌过期,获取接口请求数据在定义的数组中查找判断请求类型是否需要无痛刷新 // 6.index===-1则表示在数组中没有找到也就不需要无痛刷新,直接跳到登入页面进行登入 // 7.index!==-1则表示需要无痛刷新,将状态管理中存储的用户账号和密码解构出来, // 进行登入接口请求从而达到重新获取令牌,进而达到不需要进入登入页面就可以进行登入请求也就达到无痛刷新的效果 // 需要无痛刷新的操作页面 const METHOD_TYPE = ["_mt=edit", "_mt=create", "_mt=delete"] // 响应拦截器 instance.interceptors.response.use(async function (response) { let data = response.data//强解 let { errno, errmsg } = data//结构赋值 let path = router.currentRoute.value.fullPath//获取路径 console.log(errno,'errno'); if (10006 == errno) { // 获取接口请求数据 const configData = response.config.data || '' // 判断请求类型是否需要无痛刷新,index !== -1则需要无痛刷新 let index = METHOD_TYPE.findIndex(item => configData.includes(item)) if (-1 === index) {//需要重新登入获取令牌 router.replace({ path: "/login", query: { back: path } })//登入后需要跳回的地址 return } else {//需要无痛刷新令牌 const store = useUserStore(); const { username, password } = store.loginInfo//在状态管理里面定义一个loginInfo // 1.重新获取令牌 let loginData = { _gp: 'admin', _mt: 'login', username, password }; const { errno, errmsg, data } = await post(loginData)//这里是通过async 将异步序列化改为同步 if (200 == errno) { Cookies.set('token', data)//保存令牌 } else { console.log(55); router.replace({ path: "/login", query: { back: path } })//登入后需要跳回的地址 return Promise.reject({ errno, errmsg,data}) } return instance.request(response.config) } } return data }, function (error) { console.error('响应错误', error) return Promise.reject(error) } ) function get(params?: object): Promise<TypeResponse> { return instance.get("", { params }) } function post(data: object, params?: object): Promise<TypeResponse> { return instance.post("", qs.stringify(data), { params }) } /** * 富文本框图片上传请求 */ export function upload(data: object): Promise<TypeResponse> { return instance.post("http://192.168.1.188:8080/upload/admin", data); } export { get, post }
以上がvue3+ts+axios+pinia を使用して無意味なリフレッシュを実現する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。