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 相关文章推荐
jquery EasyUI的formatter格式化函数代码
Jan 12 Javascript
Javascript操作cookie的函数代码
Oct 03 Javascript
jQuery动态添加删除select项(实现代码)
Sep 03 Javascript
详解js界面跳转与值传递
Nov 22 Javascript
Javascript计算二维数组重复值示例代码
Dec 18 Javascript
JavaScript中this的用法实例分析
Dec 19 Javascript
微信小程序tabBar用法实例详解
Dec 04 Javascript
vue移动端弹框组件的实例
Sep 25 Javascript
Angular刷新当前页面的实现方法
Nov 21 Javascript
vue微信分享出来的链接点开是首页问题的解决方法
Nov 28 Javascript
优雅地使用loading(推荐)
Apr 20 Javascript
微信小程序工具函数封装
Oct 28 Javascript
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
PHPShop存在多个安全漏洞
2006/10/09 PHP
PHP has encountered a Stack overflow问题解决方法
2014/11/03 PHP
PHP生成RSS文件类实例
2014/12/05 PHP
完美解决thinkphp验证码出错无法显示的方法
2014/12/09 PHP
ThinkPHP实现转换数据库查询结果数据到对应类型的方法
2017/11/16 PHP
Ubuntu中支持PHP5与PHP7双版本的简单实现
2018/08/19 PHP
jquery的Theme和Theme Switcher使用小结
2010/09/08 Javascript
jquery乱码与contentType属性设置问题解决方案
2013/01/07 Javascript
『jQuery』.html(),.text()和.val()的概述及使用
2013/04/22 Javascript
qq悬浮代码(兼容各个浏览器)
2014/01/29 Javascript
js中回调函数的学习笔记
2014/07/31 Javascript
javascript几个易错点记录
2014/11/26 Javascript
javascript每日必学之基础入门
2016/02/16 Javascript
NodeJS和BootStrap分页效果的实现代码
2016/11/07 NodeJs
原生JS实现跑马灯效果
2017/02/20 Javascript
JavaScript实现一个空中避难的小游戏
2017/06/06 Javascript
详解vue-cli 脚手架项目-package.json
2017/07/04 Javascript
JavaScript模拟文件拖选框样式v1.0的实例
2017/08/04 Javascript
Angular使用cli生成自定义文件、组件的方法
2018/09/04 Javascript
微信小程序实现底部导航
2018/11/05 Javascript
图文讲解用vue-cli脚手架创建vue项目步骤
2019/02/12 Javascript
element-ui多文件上传的实现示例
2019/04/10 Javascript
在vue-cli 3中给stylus、sass样式传入共享的全局变量
2019/08/12 Javascript
layui自定义工具栏的方法
2019/09/19 Javascript
[47:02]2018DOTA2亚洲邀请赛3月29日 小组赛B组 VP VS paiN
2018/03/30 DOTA
深入浅出学习python装饰器
2017/09/29 Python
对Python random模块打乱数组顺序的实例讲解
2018/11/08 Python
Python hashlib加密模块常用方法解析
2019/12/18 Python
tensorflow实现测试时读取任意指定的check point的网络参数
2020/01/21 Python
使用CSS3制作一个简单的Chrome模拟器
2015/07/15 HTML / CSS
Europcar葡萄牙:葡萄牙汽车和货车租赁
2017/10/13 全球购物
施工资料员岗位职责
2014/01/06 职场文书
群众路线剖析材料(四风问题)
2014/10/08 职场文书
2015年助理政工师工作总结
2015/05/26 职场文书
2019年公司卫生管理制度样本
2019/08/21 职场文书
Vue+TypeScript中处理computed方式
2022/04/02 Vue.js