Home  >  Article  >  Web Front-end  >  How to use vue3+ts+axios+pinia to achieve senseless refresh

How to use vue3+ts+axios+pinia to achieve senseless refresh

PHPz
PHPzforward
2023-05-25 15:37:061592browse

vue3 ts axios pinia achieves senseless refresh

1. First download aiXos and pinia in the project

npm i pinia --save
npm install axios --save

2. Encapsulate axios request-----

Download 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(&#39;&#39;, { params });
};
function post(data: object, params?: object): Promise<TypeResponse> {
    return instance.post(&#39;&#39;, qs.stringify(data), { params });
};
 
 
//暴露实列
export {
    post, get,
}

3.qs.stringify(data) is to convert the requested data into a form format. If you don’t need it, just remove it directly;

4. Log in again and jump Routing needs to be set, if not needed you can remove

5. State management--data

Download persistence tool

npm install pinia-plugin-persistedstate --s

Configure persistence in main.js

//引入数据持久化插件
import piniaPluginPersistedstate from &#39;pinia-plugin-persistedstate&#39;;
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate);
app.use(pinia)
import { defineStore } from &#39;pinia&#39;
export const useUserInfoStore = defineStore(&#39;UserInfo&#39;, {
    state:() => ({
       
        LoginInfo:{
            username:&#39;&#39;,
            password:&#39;&#39;
        }
      }),
     
      persist:true;//状态存储持久化
})

6. Login page--Storage form data, that is, user Name and password

npm i lodash --s
import Cookies from &#39;js-cookie&#39;;//引入cookie
import * as _ from &#39;lodash&#39;;//防抖节流插件
import {post} from &#39;@/util&#39;;
import {useUserInfoStore} from &#39;@/stores/modules/UserInfo&#39; ;//用户信息
import { useRouter,useRoute } from &#39;vue-router&#39; ;//引入路由
//这里是表单输入的数据
const ruleForm = reactive({
    password: &#39;123456&#39;,
    username: &#39;admin&#39;
});
//请求接口数据
let data = {
    _gp: "admin",
    _mt: &#39;login&#39;,
    ...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(&#39;token&#39;, token, { expires: time });
            Object.assign(LoginInfo,ruleForm)
            if (route.query.back) { //如果存在参数
             let paths = route.query.back+&#39;&#39;//拼接字符串
             console.log(paths);
             if (paths==&#39;/&#39;) {
//因为我的home是&#39;/&#39;,所有需要判断
                router.replace(&#39;/Surface&#39;)//跳转至主页
                return
             }else{
                router.replace(paths)//则跳转至进入登录页前的路由
             }
             
           } else {
            router.replace(&#39;/Surface&#39;)//否则跳转至首页
           }
            
        } else {
            ElMessage.error(errmsg)
        }
    }).catch((err:any) => {
        ElMessage.error(&#39;登录异常!&#39;)
    })
    let info = {//用户信息请求信息接口数据
        _gp: "admin",
        _mt: &#39;info&#39;,
    }
//下面这个函数是请求用户信息的,不需要可以不写
    await post(info).then((res:any) => {
        let {data} = res
        console.log(data);
        infos(data)
 
    }).catch((err:any)=>{
        ElMessage.error(&#39;登录异常!&#39;)
    })
}
//防抖节流
const fangdou = _.debounce(init, 1500, {
    leading: true,  // 延长开始后调用
    trailing: false  // 延长结束前调用
})
//移除组件时,取消防抖
onUnmounted(() => {
    fangdou.cancel()
})

7.main.js Set routing guard

import Cookie from &#39;js-cookie&#39;
import router from &#39;./router&#39;//引入路由
 
//路由守卫
router.beforeEach(async (to, from ) => {
    let tokent:string|undefined = Cookie.get(&#39;token&#39;)
    if (!tokent && to.path == &#39;/login&#39;) {
        return  true
    }
    // 没有登录,强制跳转登录页
    if (!tokent && to.path !== &#39;/login&#39;) {
        router.replace({path:&#39;/login&#39;,query:{back:to.path}});
    }
    // 防止重复登录
    if (tokent && to.path === &#39;/login&#39;) {
        return {
            path: from.path ? from.path : &#39;/Surface&#39;
        }
    }
    return true
})

That’s about it

vue3 painless refresh (senseless refresh)

The principle of painless refresh: when the token expires, the response interceptor re-makes the login request through judgment

Implementation process

Define a loginInfo object in the state management state to store the user's account and password

//在状态管理文件中
import { defineStore } from &#39;pinia&#39;
import Cookies from "js.cookie"
import {post} from &#39;@/http&#39;
 
import router from &#39;@/router&#39;;
import { ElMessage } from &#39;element-plus&#39;;
export const useUserStore = defineStore({
  id: "userStore",
  persist: {
    paths:[&#39;user&#39;]
  },//持久化
  state: () => ({
    loginInfo:{
      username:&#39;&#39;, 
      password:&#39;&#39;
    }
  }),
  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(&#39;/login&#39;)
          ElMessage.success(errmsg);
        }else{
          ElMessage.error(errmsg);
        }
      }).catch(res=>{
      console.log(res,"退出登入失败");
      })
    }
  }
})

In the login page, after the login request is successful, the user's account and password are stored in the status management

//在登入页面文件中
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)
    }
})

3. In http, first define an array variable, which stores Operations that require painless refresh include: delete, add, edit

4. In the response interceptor, determine whether 10006 is equal to errno. If equal, the token has expired, otherwise it has not expired

5. The token expires. Get the interface request data and search it in the defined array to determine whether the request type requires painless refresh.

6.index===-1 means it is not found in the array, so there is no need to refresh it. Painful refresh, jump directly to the login page to log in

7.index! ==-1 means a painless refresh is required, deconstructing the user account and password stored in the status management, making a login interface request to re-obtain the token, and then making a login request without entering the login page. The effect of painless refresh

//在封装的http文件中
import axios, { type AxiosResponse } from &#39;axios&#39;;
import qs from &#39;qs&#39;
import Cookies from "js.cookie"
import router from &#39;@/router&#39;;
import { ElMessage } from &#39;element-plus&#39;;
import { useUserStore } from &#39;@/stores/admin&#39;;
 
declare interface TypeResponse extends AxiosResponse {
    url(url: any): unknown;
    [x: string]: any;
    /**
     * 错误号,200表示成功,10006令牌过期
     */
    errno: number,
    /**
     * 失败返回的消息
     */
    error: string,
    /**
     * 成功后返回的消息
    */
    errmsg: string
 
}
let baseURL = &#39;&#39;
 
if (process.env.NODE_ENV === "development") {
    baseURL = &#39;/m.api&#39;
} 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[&#39;AdminToken&#39;] = Cookies.get("token") + &#39;&#39;
    }
    return config
}, function (error) {
    console.error(&#39;请求错误&#39;, 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,&#39;errno&#39;);
    
    if (10006 == errno) {
        // 获取接口请求数据
        const configData = response.config.data || &#39;&#39;
        // 判断请求类型是否需要无痛刷新,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: &#39;admin&#39;, _mt: &#39;login&#39;, username, password };
            const { errno, errmsg, data } = await post(loginData)//这里是通过async 将异步序列化改为同步
            if (200 == errno) {
 
                Cookies.set(&#39;token&#39;, 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(&#39;响应错误&#39;, 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 }

The above is the detailed content of How to use vue3+ts+axios+pinia to achieve senseless refresh. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete