axios拦截器

522 阅读4分钟

前言

几乎现在使用到axios的项目都会需要写一个request.js的文件,作为请求接口必引的文件,里面会包含请求拦截器和响应拦截器。

什么是拦截器

拦截器分为请求拦截器和响应拦截器。顾名思义,请求拦截器就是在执行发请求的命令之后和请求发出之前的这一段时间要进行的操作,常见的是在此阶段中,在请求header中增加用户token(Authorization也类似)。只要为axios实例添加拦截器每个api请求都会执行拦截器。执行顺序: 请求拦截器 -> api请求 -> 响应拦截器
请求拦截器:发出请求命令 -> 请求拦截 -> 发送请求,
响应拦截器:请求结束响应返回 -> 响应拦截 -> 响应成功的业务逻辑代码
使用方式如下

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
}, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
});

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
}, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
});

拦截器还可以取消, Axios拦截器提供了eject方法取消拦截函数(eject需要传入id做为参数,id是个use函数的返回值)

const interceptorId = axios.interceptors.request.use(function () {/*...*/}); 
axios.interceptors.request.eject(interceptorId);

拦截器的用途

响应拦截器对后端状态码拦截, 比如后端返回404状态码, 跳转到404页面。

axios.interceptors.response.use((res) => {
  return res
}, err => {
  if (err.response.status === 404) {
    router.replace({
      path: '/404.html'
    })
  }
})

统计请求耗时, 可以统计api从发起请求到返回数据需要的时间,这种比较集中的逻辑就适合用拦截器来做了,统一处理如果以后要改也非常容易。

axios.interceptors.request.use((config) => {
  // api请求开始的时间
  config.metadata = { startTime: new Date() }
  return config;
});
axios.interceptors.response.use((res) => {
  // api请求结束的时间
  res.config.metadata.endTime = new Date()
  const { startTime, endTime } = res.config.metadata
  // 计算请求耗时的时间
  console.log(endTime - startTime)
  return res
});

实现步骤

1.安装axios
npm install axios --save

2.引入模块
在utils文件夹中创建request.js文件,引入axios模块
import axios from "axios";

3.创建axios实例

const service = axios.create({
    // 根据 process.env.NODE_ENV 区分状态,切换不同的 baseURL
    baseURL: process.env.NODE_ENV === 'production' ? `/` : '/apis',
    // 超时时间 单位是ms
    timeout: 2000, 
    // // 跨域请求时是否需要使用凭证
    // withCredentials: true,
    // // 设置请求头
    // headers: {
    //   get: {
    //     'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
    //   },
    //   post: {
    //     'Content-Type': 'application/json;charset=utf-8'
    //   }
    // },
    // // 在向服务器发送请求前,序列化请求数据
    // transformRequest: [function (data) {
    //   data = JSON.stringify(data)
    //   return data
    // }],
    // // 在传递给 then/catch 前,修改响应数据
    // transformResponse: [function (data) {
    //   if (typeof data === 'string' && data.startsWith('{')) {
    //       data = JSON.parse(data)
    //   }
    //   return data
    // }],
})

4.请求拦截器
请求拦截器可以用来配置公共的请求头,加载弹窗等, 比如 import { Toast, Indicator } from "mint-ui";

service.interceptors.request.use(config => {
  Indicator.open({  //加载提示框
    text: '加载中...',
    spinnerType: 'fading-circle'
  });
  config.headers = {
    'Content-Type': 'application/x-www-form-urlencoded' //配置请求头
  }
  return config;
}, error => {
  Promise.reject(error);
});

5.响应拦截器
响应拦截器可以用来针对后端返回的类型做统一的处理,比如给一些提示;
请求拦截里如果加了加载框,这里也可以统一关闭;

service.interceptors.response.use(response => {
  Indicator.close();  //关闭加载框
  if (response && response.status) {
    //这里可以做统一的处理
  } 
  return response.data
}, error => {
  Indicator.close();  //关闭加载框
  Toast({
    message: "网络错误!",
    iconClass: "icon_fail",
    duration: 2000,
  });
  return Promise.resolve(error.response);
})

完整代码示例

// http.js 
import axios from 'axios' 
// 创建 axios 实例 
const service = axios.create({ 
})
const service = axios.create({
    // 根据 process.env.NODE_ENV 区分状态,切换不同的 baseURL 
    baseURL: process.env.NODE_ENV === 'production' ? `/` : '/apis', 
    // 请求 30s 超时
    timeout: 30000,
    // // 跨域请求时是否需要使用凭证
    // withCredentials: true,
    // // 设置请求头
    // headers: {
    //   get: {
    //     'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
    //   },
    //   post: {
    //     'Content-Type': 'application/json;charset=utf-8'
    //   }
    // },
    // // 在向服务器发送请求前,序列化请求数据
    // transformRequest: [function (data) {
    //   data = JSON.stringify(data)
    //   return data
    // }],
    // // 在传递给 then/catch 前,修改响应数据
    // transformResponse: [function (data) {
    //   if (typeof data === 'string' && data.startsWith('{')) {
    //       data = JSON.parse(data)
    //   }
    //   return data
    // }],
})

// 请求拦截器
service.interceptors.request.use((config) => {
    // 在此可以添加请求头参数
    config.headers['Access-Token'] = sessionStorage.token;
    
    return config
}, (error) => {
    // 错误抛到业务代码
    error.data = {}
    error.data.msg = '服务器异常,请联系管理员!'
    return Promise.resolve(error)
})

// 响应拦截器
service.interceptors.response.use((response) => {
    const status = response.status
    let msg = ''
    // 处理msg
    
    if (status < 200 || status >= 300) {
        // 处理http错误,抛到业务代码
        
        return Promise.resolve(new Error(msg))
    } else {
        return response.data
    }
}, (error) => {
    // 错误抛到业务代码
    error.data = {}
    error.data.msg = '请求超时或服务器异常,请检查网络或联系管理员!'
    return Promise.resolve(error)
})

总结

Axios拦截器的思想是通过对数组中成员进行一定的排列,然后遍历执行,以达到一定的执行顺序。