用 axios 拦截器统一处理 Token 和错误提示

最近在开发 QQ 机器人和它的管理面板,面板是前后端分离的,前端用 Vue.js + Axios + element-ui。

API 每次请求都需要带 Bearer Token,还要配置请求地址。如果每个页面发请求时都自己写一遍 header 和错误处理,重复很多,登录超时的处理也散在各处。于是我在 src/ 目录下新建了一个 axios-init.js,用于初始化 axios 并导出实例,把这些事集中在拦截器里做。

src/axios-init.js

import axios from 'axios'
import router from '@/router'  //引入router
import cookies from 'vue-cookies'
import { Notification } from 'element-ui';

let instance = axios.create(); //创建Loading 的实例
instance.defaults.baseURL = "http://localhost/api/"; // 配置axios请求的地址
instance.defaults.headers.post['Content-Type'] = 'application/json; charset=utf-8';
axios.defaults.crossDomain = true;
axios.defaults.withCredentials = true;  //设置cross跨域 并设置访问权限 允许跨域携带cookie信息
instance.defaults.headers.common['Authorization'] = ''; // 设置请求头为 Authorization

// 请求拦截器
instance.interceptors.request.use(
  config => {
    // 每次发送请求之前判断vuex中是否存在token
    const token = cookies.get('token');
    token && (config.headers.Authorization = 'Bearer '+ token);
    return config;
  },
  error => {
    return Promise.error(error); // 抛出错误
  }
);

instance.interceptors.response.use(
  response => {
    // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
    // 否则的话抛出错误
    // 如果返回的状态码和body中的code不一致,说明接口请求失败,抛出错误
    if (response.status === 200 && response.data.code !== 200) {
      switch (response.data.code) {
        case 1001:
          cookies.remove('token');
          cookies.remove('userId');
          cookies.remove('userName');
          router.push({path: '/login'});
          Notification({
            title: '登录超时',
            message: '请尝试重新登录',
            type: 'warning'
          });
          break;
        default:
          Notification({
            title: '提示',
            message: response.data.message,
            type: 'error'
          });
      }
      return Promise.reject(response);
    } else if (response.status === 200 && response.data.code === 200) {
      return Promise.resolve(response);
    }
  },
  error => {
    // 如果请求失败,返回错误
    return Promise.reject(error);
  }
);

export default instance

axios.create() 创建一个独立的实例,baseURL、header 这些配置只挂在这个实例上。之后所有请求都走它,路径只写 /member/list 这种相对路径。

请求拦截器做的事只有一件:每次发请求之前从 cookie 里取出登录时存的 token,有就塞进 Authorization 头,格式是 Bearer <token>

响应拦截器要多说两句。API 的约定是 HTTP 状态码都返回 200,业务结果放在 body 的 code 字段里,200 是成功。拦截器按 code 分三种情况:

  • 200:正常返回,页面拿到数据
  • 1001:登录超时。清掉 cookie 里的 token 和用户信息,跳到登录页,弹一个「登录超时」的警告通知
  • 其他:把服务端返回的 message 用 element-ui 的 Notification 弹出来,类型是 error

后两种都 Promise.reject,页面里的 .then 不会执行,页面也就不用再写一遍错误提示。

最后在 main.js 里引入导出的 instance,挂到 Vue 原型上。

src/main.js

import instance from "./axios-init";
Vue.prototype.$http = instance;

组件里用 this.$http.get('/xxx')this.$http.post('/xxx', data) 发请求,Token 和错误提示都不用管。

头图/Cover

Photo by DS stories on Pexels

评论

评论加载中…

输入关键词开始搜索。

选择Enter 打开Esc 关闭CtrlK 唤起