vue axios最全拦截器封装 请求头配置 异常状态统一处理 loading设置

注意点:不要直接对axios原型设置拦截,先创建axios实例: axios.create
然后分别用到:
service.interceptors.request.use
service.interceptors.response.use

拦截器代码:

import axios from 'axios';
import router from '../router';
import db from '@/utils/localstorage';
import { MessageBox, Message, Loading } from 'element-ui';
import store from '@/store';
import { getToken } from '@/utils/auth';
var aaa = 0
let nowUrl = '';

// 创建axios实例
const service = axios.create({
  // baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // 跨域请求时发送cookie
  baseURL: config.BASE_API,
  timeout: 30000 // 请求超时
});

// 请求拦截器
let loadingInstance = null;
service.interceptors.request.use(
  (config) => {
    nowUrl = config.url;
    // do something before request is sent
   
    var xtoken = localStorage.getItem('loginToken');
    config.headers['tenantPath'] = (window.location.pathname.split('/')[1] === 'sdm' ? window.location.pathname.split('/')[2] : window.location.pathname.split('/')[1]) || '';
    config.headers['t'] = store.getters.t;
    if (xtoken != null) {
      config.headers['X-User'] = getToken();
      config.headers['System'] = 'M';
      config.headers['crmversion'] = 'V1.0.0';
      config.headers['channel'] = 'PC';
      config.headers['Content-Type'] = 'application/json';
    }
  
    if (config.responseType === 'blob') {  // blob类型 延长超时时间
      config.timeout = 60000;
      loadingInstance = Loading.service({
        lock: true,
        text: 'Loading',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      });
    }
    if (config.url.includes('add') || config.url.includes('edit') || config.url.includes('update') || config.url.includes('create')) {
      loadingInstance = Loading.service({
        lock: true,
        text: 'Loading',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      });
    }
    if (config.url.indexOf('entrust/query/pagination')) {
      config.timeout = 300000;
    }
    if (config.url.includes('/member/import') || config.url.includes('/dataSetRoler/import')) { // 导入文件设置请求头
      config.headers['Content-Type'] = 'multipart/form-data';
    }
    return config;
  },
  (error) => {
    // 处理请求错误
    console.log(error); // for debug
    return Promise.reject(error);
  }
);

// 响应拦截器
service.interceptors.response.use(
  /**
   * 如果您想获得http信息,例如头信息或状态信息
   * 请返回 response => response
   */

  /**
   * 通过自定义代码确定请求状态
   * 这里只是一个例子
   * 还可以通过HTTP状态代码来判断状态
   */
  (response) => {
    if (response.config.responseType === 'blob') {  // 下载时直接return 返回blob
      loadingInstance && loadingInstance.close();
      return response.data;
    }
    if (response.config.url.includes('add') || response.config.url.includes('edit') || response.config.url.includes('update') || response.config.url.includes('create')) {
      loadingInstance && loadingInstance.close();
    }
    const res = response.data;
    // 如果状态码不是0,则判断为错误。
    if (res.status !== 0 && res.status !== 200) {
      if (res.status == '400') {
        Message.closeAll(); // 关闭之前的弹出信息
        Message({
          dangerouslyUseHTMLString: true,
          message: res.message || 'Error',
          type: 'error',
          duration: 5 * 1000
        });
      }

      // 50008: 非法的令牌; 50012: 其他客户端登录; 50014: 令牌过期;
      if (res.code === 401 || res.code === 50012 || res.code === 50014) {
        // 重新登陆
        MessageBox.confirm('很抱歉,登录已过期,请重新登录', {
          confirmButtonText: '重新登录',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          store.dispatch('user/resetToken').then(() => {
            location.reload();
          });
        });
      }
      return Promise.reject(res);
    } else {
      return res;
    }
  },
  (error) => {
    console.log('err' + error.request.response); // for debug
    if (!error.request.response) {
      Message({
        message: '服务连接失败',
        type: 'error',
        duration: 5 * 1000
      });
      return Promise.reject(error);
    }
    const err = JSON.parse(error.request.response);
    loadingInstance && loadingInstance.close();
    if (nowUrl.indexOf('/menu/getList') != '-1') {
      return Promise.reject(error);
    } 
    if (error.request &&
      error.request.response &&
      JSON.parse(error.request.response) &&
      JSON.parse(error.request.response).status === 600 &&
      JSON.parse(error.request.response).message) {
      return Promise.reject(error);
    }
    if (err.status === 401 && nowUrl.indexOf('/menu/getList') == '-1') {
      // 重新登陆
      if (aaa == 0) {
        aaa++
        MessageBox.confirm('很抱歉,登录已过期,请重新登录', {
          confirmButtonText: '重新登录',
          showCancelButton: false,
          type: 'warning'
        }).then(() => {
          db.remove('router')
          db.remove('loginToken')
          aaa = 0
          router.push({ path: '/login' });
        });
      }
      return Promise.reject(error);
    }
   
    if (
      error.request &&
      error.request.response &&
      JSON.parse(error.request.response) &&
      JSON.parse(error.request.response).status == 400 &&
      JSON.parse(error.request.response).message
    ) {
      Message({
        message: JSON.parse(error.request.response).message,
        type: 'error',
        duration: 5 * 1000
      });
      return Promise.reject(error);
    }
    if (error.message.indexOf('timeout') !== -1) {
      Message({
        message: '请检查网络后重试',
        type: 'error',
        duration: 5 * 1000
      });
      return Promise.reject(error);
    } else {
      Message({
        message: JSON.parse(error.request.response).message,
        type: 'error',
        duration: 5 * 1000
      });
      return Promise.reject(error);
    }
  }
);

export default service;

上面我们对响应状态 401 500 其他等状态的错误处理封装的很详细,以及code异常时的提示都做了处理;
在调用时不需要再处理 异常status 或者异常code 的情况,小心页面上发生两次错误提示哈!

注意上面是 export default service; 有default, 所以我们在api文件里引用时 import request from '@/utils/request' ,这里的request可以是任何自定义的名称~

调用接口代码:manage.js

import request from '@/utils/request'
const prefix = 'web'

export function getKey() {
  return request({
    url: prefix + '/member/ldap/getKey',
    method: 'get'
  });
}

export function getValidCode(data) {
  return request({
    url: prefix + '/captcha',
    method: 'get',
    data
  });
}

封装到上面的程度后,每次调用接口时需要 把manage.js 里的方法一个个import进来,非常不方便
可以看我下篇笔记,只需要一步一次输出manage.js文件所有方法,在调用时就不需要逐个引入啦

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339

推荐阅读更多精彩内容