步骤如下:
1-token过期根据refresh_token获取新的token 重新获取数据
2-创建一个新的axios实例 【使用request防止再次进入请求拦截和请求响应而进入死循环】
3-根据请求相应的响应值 是不是401 是:说明token过期
然后进行判断store中的 user :{token:’*****’,refresh_token:’******’}中的 refresh_token和user对象是否存在 ,如果不存在说明之前没有登录过,直接去登录
4-使用新创建的axios 实例对象 requestFreshToken 发送新的请求 headers中的口令携带的是 refresh_token
5-获取token之后 将值重新赋值给user中的token
6-将user重新存入store中
7-重新获取刚才因为token失效而没有获取的数据 直接使用request 参数 来自error对象中【这里保存了之前token失效的请求数据】
具体实现 代码如下:
- import Vue from 'vue'
- import axios from 'axios'
- import router from '@/router'
- import {
- ACCESS_TOKEN,
- FRESH_TOKEN
- } from '@/store/mutation-types'
- import {
- Message
- } from 'element-ui';
- // somefile.js
- import ls from '@/utils/localStore.js';
- const defaultSettings = require("@/settings.js");
-
-
- let apiBaseUrl = process.env.VUE_APP_BASE_API
-
- let isRefreshing = false //是否正在刷新token
-
- let callbacks = [] //失效后同时发送请求的容器 --- 缓存接口
- // 刷新 token 后, 将缓存的接口重新请求一次
- function onAccessTokenFetched() {
- callbacks.forEach(callback => {
- callback()
- })
- callbacks = [] // 清空缓存接口
- }
-
- // 添加缓存接口
- function addCallbacks(callback) {
- callbacks.push(callback)
- }
- // 请求函数
- function request(url, options) {
- const token = ls.get(ACCESS_TOKEN)
- const defaultOptions = {
- withCredentials: true,
- url: url,
- baseURL: apiBaseUrl,
- };
- const newOptions = {
- ...options,
- ...defaultOptions
- };
-
-
- newOptions.headers.token = token;
- return axios.request(newOptions)
- .then(checkStatus)
- .catch(error => console.log(error));
- }
-
- function checkStatus(error) {
- if (error.response) {
- const response = error.response
- const refreshToken = ls.get(FRESH_TOKEN);
- if (response && response.status == 401) {
- // 刷新token的函数,这需要添加一个开关,防止重复请求
- if (!isRefreshing) {
- isRefreshing = true;
- axios({
- baseURL: apiBaseUrl,
- url: `/reLogin/${refreshToken}`,
- method: 'post'
- }).then(response => {
- const res = response.data;
- isRefreshing = false;
- if (res.code == '200') {
- ls.set(ACCESS_TOKEN, res.data.access_token)
- onAccessTokenFetched()
- } else {
- // 登出
- ls.clear()
- router.replace({
- path: '/login'
- })
- }
- }).catch(error => {
- console.log("刷新token异常", error)
- // 跳转到首页
- ls.clear()
- console.log('request router', router)
- router.replace({
- path: '/login'
- })
-
- });
- }
- isRefreshing = true;
- const options = response.config;
- const url = options.url.replace(process.env.VUE_APP_BASE_API, '')
- // 这个Promise函数很关键
- const retryOriginalRequest = new Promise((resolve) => {
- console.log('resolve', resolve)
- addCallbacks(() => {
- resolve(request(url, options))
- })
- });
- return retryOriginalRequest;
- } else {
- // message 诺到里面,401不报错
- Message.closeAll()
- Message({
- message: response.data.msg,
- type: 'error'
- }, true)
- return Promise.reject(error)
- }
- }
- return error.data;
- // return error;
-
- }
-
- // 创建一个axios实例
- const service = axios.create({
- baseURL: apiBaseUrl,
- withCredentials: true, // 跨域请求时发送Cookie
- timeout: 50000 // request timeout
- })
-
- //请求拦截器
- service.interceptors.request.use(
- config => {
- // 在发送请求之前做一些事情
- if (ls.get(ACCESS_TOKEN)) {
- // 让每个请求都带有token
- config.headers['token'] = ls.get(ACCESS_TOKEN)
- } else if (process.env.NODE_ENV === 'development' && defaultSettings.noToken) {
- // console.log('没有token--------', process.env.NODE_ENV)
- config.headers['swagger_user_name'] = defaultSettings.swagger_user_name
- config.headers['swagger_user_pwd'] = 1
- }
- config.autoCatchErr = true;
- return config
- },
- error => {
- console.log(error) // for debug
- return Promise.reject(error)
- }
- )
- // 响应拦截器
- service.interceptors.response.use(
- response => {
- const res = response.data;
- // 增加res.response,zq-el-ui中的下载请求会用到
- res.response = response;
- if (response.status == 200 && response.config.params && response.config.params.no_interception_response) {
- return response.data
- }
- // 文件下载
- if (response.status == 200 && response.request.responseType == "blob" || response.request.responseType == "arraybuffer") {
- return response.data
- }
- // 正常返回
- if (response.data.body && response.data.body.rtnCode === '0000') {
- return response.data.body.dataSet
- }
- if (res.code == 200) {
- if (res.msg) {
- Message({
- message: res.msg,
- type: 'success'
- }, true)
- }
- return res
- } else {
- if (response.config.autoCatchErr) {
- Message.closeAll()
- Message({
- message: res.msg,
- type: 'error'
- }, true)
- console.log('请求失败', res)
- //
- // throw new Error('接口报错:::', res);
- return res
- } else {
- Message({
- message: res.msg,
- type: 'error'
- }, true)
- return res
-
- }
- }
- },
- error => {
- return checkStatus(error)
- }
- )
-
- export default service