JavaScript

超轻量级php框架startmvc

vue下axios拦截器token刷新机制的实例代码

更新时间:2020-10-01 02:30:01 作者:startmvc
//创建http.js文件,以下是具体代码://引入安装的axios插件importaxiosfrom'axios'importrouterfrom'@/rou

//创建http.js文件,以下是具体代码:


//引入安装的axios插件
import axios from 'axios'
import router from '@/router';
import Vue from 'vue'
const qs = require("qs");
let _this = new Vue();
let isLock = false;
let refreshSubscribers = [];
//判断token是否过期
function isTokenExpired(token) {
 let expires_time = JSON.parse(token).expires_time;
 let curentTime = new Date().getTime();
 if (curentTime >= expires_time) {
 return true;
 } else {
 return false;
 }
}
//获取Token对象
function getToken() {
 return localStorage.getItem("token");
}
//push所有请求到数组中
function subscribeTokenRefresh(cb) {
 refreshSubscribers.push(cb)
}

//刷新请求(refreshSubscribers数组中的请求得到新的token之后会自执行,用新的token去请求数据)
function onRrefreshed(token) {
 refreshSubscribers.map(cb => cb(token))
}
//刷新token
function refreshToken(config, token, resolve, reject) {
 let data = { refresh_token: JSON.parse(token).refresh_token };
 axios({
 method: "post",
 url: "xxxxxx/refreshToken",//刷新token的接口
 headers: {
 "Content-Type": "application/x-www-form-urlencoded",
 "Authorization": "Basic b3JkZXItc2VydmVyOjEyMzQ1Ng=="
 },
 data: qs.stringify(data)
 }).then(res => {
 isLock = false;//释放锁
 if (res.data.code === 101) {
 _this.$message.error('登录状态已失效,请重新登录。');
 localStorage.removeItem("token");
 router.push({
 path: "/login"
 });
 return;
 }

 let expires_time = new Date().getTime() + parseInt(res.data.data.expires_in * 0.8) * 1000;
 let token = JSON.parse(localStorage.getItem("token"));
 token.expires_time = expires_time;
 token.access_token = res.data.data.access_token;
 localStorage.setItem("token", JSON.stringify(token));

 config.headers.Authorization = 'Bearer ' + res.data.data.access_token;
 resolve(config);
 //执行数组里的函数,重新发起被挂起的请求
 onRrefreshed(res.data.data.access_token)
 //清空数组中保存的请求
 refreshSubscribers = []
 }).catch(err => {
 return err;
 });
}

function request(newOptions, resolve, reject) {
 axios({
 method: newOptions.method,
 url: newOptions.url,
 data: newOptions.type == "form" ? qs.stringify(newOptions.data) : newOptions.data,
 headers: newOptions.headers
 }).then(res => {
 if (res.status == 200) {
 //这里我们只需要获取返回的data中的数据即可
 resolve(res.data);
 } else {
 reject(res.data);
 }
 }).catch(err => {
 reject(err);
 _this.$message.error('服务异常!');
 })
}

axios.interceptors.request.use(
 config => {
 let token = getToken();
 if (token) {
 //判断token是否过期,如果过期请求刷新token
 if (isTokenExpired(token)) {
 //判断当前是否正在请求刷新token
 if (!isLock) {
 isLock = true;//isLock设置true,锁住防止死循环。
 //使用Promise等待刷新完成返回配置信息
 let refresh = new Promise((resolve, reject) => {
 refreshToken(config, token, resolve, reject);
 })
 return refresh;

 } else {
 //判断当前url是否是刷新token的请求地址,如果是直接下一步。
 if (config.url.indexOf('/logined/refreshToken') === -1) {
 //把请求(token)=>{....}都push到一个数组中
 let retry = new Promise((resolve, reject) => {
 //(token) => {...}这个函数就是回调函数
 subscribeTokenRefresh((token) => {
 config.headers.Authorization = 'Bearer ' + token
 //将请求挂起
 resolve(config)
 })
 })
 return retry

 } else {
 return config;
 }
 }

 } else {
 return config;
 }

 } else {
 return config;
 }
 }, error => {
 return Promise.reject(error);
 });
const http = options => {
 return new Promise((resolve, reject) => {
 const defaultOptions = {
 type: "json"
 };
 const newOptions = {
 ...defaultOptions,
 ...options
 };
 //headers默认传递json格式数据,这里也可以设置token,每次调用都会携带
if (localStorage.getItem("token")) {
 newOptions.headers = {
 // 'Authorization': 'Basic b3JkZXItc2VydmVyOjEyMzQ1Ng==',
 'content-Type': newOptions.type == 'form' ? 'application/x-www-form-urlencoded;charset=UTF-8' : 'application/json;charset=UTF-8',
 'Authorization': 'Bearer ' + JSON.parse(localStorage.getItem("token")).access_token,
 ...newOptions.headers
 };
 } else {
 newOptions.headers = {
 'content-Type': newOptions.type == 'form' ? 'application/x-www-form-urlencoded;charset=UTF-8' : 'application/json;charset=UTF-8',
 ...newOptions.headers
 };
 }
 request(newOptions, resolve, reject);
 })
};

//设置请求超时
axios.defaults.timeout = 30000
export default http

//在main.js下面挂载 http.js文件
import http from '@/utils/http.js';
Vue.prototype.http = http;

//登录保存token信息接口

this.http({
 method: "post",
 url: "/xxxxx/user",
 type: "form",
 headers: { Authorization:"Basicb3JkZXItc2VydmVyOjEyMzQ1Ng==" },
 data: {}
 }).then(function(res) {
 let expires_time =
 new Date().getTime() +
 parseInt(res.data.token.expires_in * 0.8) * 1000;
 let token = res.data.token;
 token.expires_time = expires_time;
 localStorage.setItem("token", JSON.stringify(token));
 
 }).catch(function(err) {
 console.log(err);
 }); 

//退出清空token
this.http({
 method: "get",
 url: "/xxxxx/logout",
 data: {}
 }).then(function(res) {
 localStorage.removeItem("token");
 }).catch(function(err) {
 console.log(err);
 });

总结

以上所述是小编给大家介绍的vue下axios拦截器token刷新机制的实例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持! 如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!