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


Posted in Javascript onJanuary 17, 2020

//创建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刷新机制的实例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
我的Node.js学习之路(四)--单元测试
Jul 06 Javascript
在AngularJS中使用AJAX的方法
Jun 17 Javascript
JavaScript中的Object对象学习教程
May 20 Javascript
简单的js表格操作
Sep 24 Javascript
微信小程序 POST请求(网络请求)详解及实例代码
Nov 16 Javascript
浅谈js基础数据类型和引用类型,深浅拷贝问题,以及内存分配问题
Sep 02 Javascript
Vue render深入开发讲解
Apr 13 Javascript
如何在Vue.js中实现标签页组件详解
Jan 02 Javascript
原生JS实现列表内容自动向上滚动效果
May 22 Javascript
基于vue-cli搭建多模块且各模块独立打包的项目
Jun 12 Javascript
js回到页面指定位置的三种方式
Dec 17 Javascript
vue使用v-model进行跨组件绑定的基本实现方法
Apr 28 Vue.js
js布局实现单选按钮控件
Jan 17 #Javascript
vue 查看dist文件里的结构(多种方式)
Jan 17 #Javascript
JavaScript数组去重实现方法小结
Jan 17 #Javascript
JS面向对象之多选框实现
Jan 17 #Javascript
JavaScript基于面向对象实现的无缝滚动轮播示例
Jan 17 #Javascript
JS面向对象之单选框实现
Jan 17 #Javascript
原生JavaScript实现的无缝滚动功能详解
Jan 17 #Javascript
You might like
PHP合并数组+与array_merge的区别分析
2010/08/01 PHP
php中使用cookie来保存用户登录信息的实现代码
2012/03/08 PHP
thinkPHP使用post方式查询时分页失效的解决方法
2015/12/09 PHP
php基于Fleaphp框架实现cvs数据导入MySQL的方法
2016/02/23 PHP
php array_pop 删除数组最后一个元素实例
2016/11/02 PHP
关于php支持的协议与封装协议总结(推荐)
2017/11/17 PHP
jquery弹出关闭遮罩层实例
2013/08/06 Javascript
JavaScript实现大数的运算
2014/11/24 Javascript
asp.net+js实现金额格式化
2015/02/27 Javascript
JavaScript中利用for循环遍历数组
2017/01/15 Javascript
vue数据控制视图源码解析
2018/03/28 Javascript
说说Vue.js中的functional函数化组件的使用
2019/02/12 Javascript
node后端服务保活的实现
2019/11/10 Javascript
微信小程序加载机制及运行机制图解
2019/11/27 Javascript
Python 基础教程之str和repr的详解
2017/08/20 Python
Python入门之三角函数atan2()函数详解
2017/11/08 Python
Python求解任意闭区间的所有素数
2018/06/10 Python
Python实现连接MySql数据库及增删改查操作详解
2019/04/16 Python
python实现五子棋人机对战游戏
2020/03/25 Python
Python实现网页截图(PyQT5)过程解析
2019/08/12 Python
Python 使用 docopt 解析json参数文件过程讲解
2019/08/13 Python
Win10下python 2.7与python 3.7双环境安装教程图解
2019/10/12 Python
sklearn和keras的数据切分与交叉验证的实例详解
2020/06/19 Python
selenium设置浏览器为headless无头模式(Chrome和Firefox)
2021/01/08 Python
Laura官网:加拿大女性的顶级时尚目的地
2019/09/20 全球购物
SQL SERVER面试资料
2013/03/30 面试题
非常详细的C#面试题集
2016/07/13 面试题
大学生实习期自我评价范文
2013/10/03 职场文书
机械设计专业应届生求职信
2013/11/21 职场文书
马云北大演讲完整版:真心话,什么才是阿里的核心竞争力?
2014/04/04 职场文书
大学生村官考核材料
2014/05/23 职场文书
体育专业自荐书
2014/05/29 职场文书
师德模范事迹材料
2014/06/03 职场文书
五一口号
2014/06/19 职场文书
2014年纠风工作总结
2014/12/08 职场文书
检举信的写法
2019/04/10 职场文书