axios封装。实现token自动刷新,统一异常处理

axios封装。实现token自动刷新,统一异常处理

  1. axios封装
//request.js
import axios from 'axios'  
import { Message } from 'element-ui'
import store from '@/store' //vuex仓库
import errorCode from './errorCode' // 异常状态码说明配置
import {getToken, getTokenCreatedTime} from '@/utils/auth' //token管理
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, //根据当前环境配置请求根路径
  // withCredentials: true, // 配置跨域是否允许cookie发送
  timeout: 1000 * 60 // 请求超时时间
})

// 是否正在刷新的标记
let isRefreshing = false;
//如果token 存在。并且token已经存在1小时。判定token需要刷新
function isOAverdue() {
  return getToken() && Date.now() - getTokenCreatedTime() > 1000 * 60 * 60
}
// 缓存token刷新中调用的接口
let subscribers = [];
// 缓存接口
function addSubscriber(callback) {
  subscribers.push(callback);
}
// 刷新 token 后, 将缓存的接口依次重新请求
function onAccessTokenFetched(newToken) {
  subscribers.forEach((callback) => {
    callback(newToken);
  });
  subscribers = [];
}

const whiteList = ['/sys/refreshToken']
//请求拦截器
service.interceptors.request.use(request => {
  // 给所有接口请求头信息加上 token
  request.headers.token = getToken();
  //token需要刷新
  if(isOAverdue() &&  !whiteList.some(item => request.url.includes(item))) {
    if(!isRefreshing) {
      isRefreshing = true;
      //调用刷新token的接口,user/refreshToken 中 刷新了token值和token的创建时间
      store.dispatch("user/refreshToken").then(() => {
        //使用新的token重新触发刷新token期间缓存的所有接口。
        onAccessTokenFetched(getToken())
      }).finally(() => {
        isRefreshing = false;
      });
    }
    /**
     * 创建一个promise并当做拦截器的返回值。该promise的状态在onAccessTokenFetched方法被执行后 推到 fulfilled。
     * 原理:axios 请求拦截器和 实际请求 会生成一个 promise 调用连。只有当请求拦截器状态走到完成,才会触发实际请求发送到服务端。
     * eg: p = new Promise((resolve, reject) => {
     *        setTimeout(() => {
     *          resolve('拦截器2')
     *        }, 3000)
     *     })
     *    Promise.resolve().then(res => '拦截器1').then(res => p).then(res => //触发请求).then(res => //响应拦截器);
     *    3秒后才会触发请求发送
     */
    const retryOriginalRequest  = new Promise((resolve, reject) => {
      addSubscriber((newToken) => {
        request.headers.token =  newToken;
        resolve(request)
      })
    })
    return retryOriginalRequest 
  }else {
    return request
  }
}, error => {
  return Promise.reject(error)
})

//响应拦截器
service.interceptors.response.use( response => {
    const status = Number(response.status) || 200  
    const message = response.data.data || response.data.msg || errorCode[status] || errorCode['default']
    // 响应异常,提示用户,并把当前接口请求状态推到异常(rejected)。Message 是 element-ui的提示组件。
    if (status !== 200 || response.data.code == 1) {
      Message({
        message: message,
        type: 'error'
      })
      return Promise.reject(error)
    }
    return response
  },
  error => {
    //登录过期。
    if (error.response && error.response.status === 401) {
      store.dispatch('user/logOut')
      return;
    }
    Message({
      message: error.message,
      type: 'error',
    })
    return Promise.reject(error)
  }
)

export default service.request

//对get请求进行封装
export const get = function (url, params){
  return new Promise((resolve, reject) => {
    service.get(url, {
      params
    }).then(res => {
      resolve(null, res.data);
    }).catch(e => {
      resolve(e.data, null)
    })
  })
}

//对post请求进行封装
export const post = function (url, data){
  return new Promise((resolve, reject) => {
    service.post(url, data).then(res => {
      resolve(null, res.data);
    }).catch(e => {
      resolve(e.data, null)
    })
  })
}
  1. api 封装
//student.js
import { get } from "../request"

export const getStudent = params => get('/student/list', params);
  1. 接口调用
//vue
import { getStudent } from "../api/student"

created(){
  this.initStudent();
},
methods: {
  async initStudent(){
    const [err, res] = await getStudent({class: '六年一班'})
    if(err){
      //接受到错误则终止后续代码执行
      return this.$message.error(err)
    }
    if(res){
      this.studentList = res.data;
    }
  }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值