axios封装技巧合集:让你的axios更好用的“七种武器”

axios如何封装才好用

前端项目中现已广泛使用axios来进行ajax请求的处理,一个很重要的问题是:

如何对axios部分进行设计,才能使得接口调用简洁,并且能够应对各种复杂的情况。

就笔者参与维护的不少项目而言,axios的封装似乎过于复杂,并且没有发挥出axios的强大功能。好用性虽则每个开发者有不同的见解,然则逻辑的清晰与否、调用是否复杂、是否易于维护等则是比较容易有一致看法的。
本文将针对axios封装的一些技巧进行分享,这些都是笔者反复实践的一些经验之谈,合理利用将利于达到事半功倍的效果。

巧妙利用配置的优先级

就axios而言,有多处可以决定最终发送出的请求的配置。首先,可以设置库的默认值,如下:

axios.defaults.timeout = 2500;

不但如此,我们还可以设置实例的默认值:

var instance = axios.create();

// 覆写库的超时默认值
// 现在,在超时前,所有请求都会等待 2.5 秒
instance.defaults.timeout = 2500;

甚至于,我们可以在请求中直接传递config 参数:

instance.get('/longRequest', {
    
    
  timeout: 5000
});

事实上,我们不但可以通过以上三种方式设置timeout参数,就axios文档中的请求配置一节中几乎所有配置,都可以按这些方式处理。
优先级:

请求的 config 参数 > 实例的 defaults 属性 > 库的默认值

这样我们完全可以设置一些默认值,而在特殊情况时再传递参数改变默认配置,这大大增加了我们发送请求的灵活性。

调用多个系统的api时如何封装

一个显然的问题是:

如果我们的系统需要调用其他系统的api,即axios的baseURL有多个,应该如何处理呢?

事实上,axios还可以创建实例,假使每个实例有不同的配置,那么调用不同的axios实例就能达到调用不同系统api的目的。

import axios from "axios";

// 配置实例1:api接口地址
var instance = axios.create({
    
    
  baseURL: process.env.VUE_APP_BASE_URL,
  timeout: 10000
});

// 配置实例2:编辑器接口地址
var editorInstance = axios.create({
    
    
  baseURL: process.env.VUE_APP_BASE_EDITOR_URL,
  timeout: 10000
});

...

export default {
    
     instance, editorInstance };

在以上案例中,我们导出了两个axios实例,这两个实例的配置并不相同,这样我们在调用axios的地方只需调用不同的实例便可以达到调用特定系统api的目的。

全局处理:妙用响应拦截器

在接收到来自后端接口的数据后,我们往往还需要做一些全局性的处理,比如自动识别出接口的报错信息,并进行全局提示;当接口状态码是405时,表明尚未登录,应跳转到登录页面等等,而拦截器可以很容易的帮我们达到这一目标。

import router from '@/router';
import {
    
     Message } from "element-ui";
// 对响应数据做点什么
function handleResSuccess(response) {
    
    
  // 专心返回data里面的数据,不关心外层
  const {
    
    
    data: {
    
     data: sucRes }
  } = response;
  return sucRes;
}
// 对响应错误做点什么
function handleResError(error) {
    
    
  const {
    
     data: errRes, status } = error.response;
  Message({
    
     type: "error", message: errRes.ret_desc });
  //对一些特殊错误码做特殊处理
  switch (status) {
    
    
    case 400:
      break;
    case 405:
      router.push({
    
     name: "login" });
      break;
    case 500:
      break;
  }
  // 这样才能被catch捕获到
  const promise = Promise.reject(errRes);
  return promise;
}
instance.interceptors.response.use(handleResSuccess, handleResError);

在以上代码中,我们对后端返回的数据格式进行了二次处理(具体的处理方式应视你的后端返回数据的格式和你的需求而定,以上仅作示例),并且对报错信息进行了全局提示,当状态码是405时,还跳转到登录页面。
值得一提的是,我们可以为多个实例设置不同的拦截器,以达到定制化的效果。

使错误信息被catch到

假设你配置了拦截器,如果你设置不当,那么你可能会使得调用axios时无法catch到其中的错误,比如

axios.get(url,{
    
    params:{
    
    id}}).then(resp=>{
    
    console.log(resp)}).catch(err=>{
    
    console.log(err)})

当你这样调用时,你的catch可能不会执行,尽管api报错了,也无法捕获。
事实上,这一点很好解决,你只需要像上面示例代码一样,在响应拦截器的错误回调handleResError中返回一个拒绝态的promise即可:

  // 这样才能被catch捕获到
  const promise = Promise.reject(errRes);
  return promise;
token的统一处理

接口权限校验的一种比较常见的方案是由前端在请求中携带token,那么

token应该放在请求体还是请求头中呢?

就axios而言,显然放在请求头(header)中是比较良好的方案。这主要是因为:

  • 像get这样的请求没有请求体,如果放在请求体中需要针对get单独进行处理。
  • 而所有的请求类型都是有请求头部的。
  • axios处理头部更为方便。

你可能会说后端开发人员设计的接口就是在请求体中携带token,但是完全可以协商后端开发人员进行改造,一个通用性的权限校验方案对于后端的清晰性也是更为有利的。
就像下面这样:

import {
    
     getStorageItem } from '@/config/storage';

var instance = axios.create({
    
    
  baseURL: process.env.VUE_APP_BASE_URL,
  timeout: 10000,
  headers: {
    
     Authorization: getStorageItem("token") }
});
及时更新token:请求拦截器

假设你像上面那样将token放在axios实例的头部,而后将axios实例挂载到vue的原型上,你可能发现:

当浏览器中的token更新,axios请求携带的token并不会更新。

原因在于创建axios实例的时机,以上往往是由于

你创建axios实例时,vue实例尚未创建,更新token(往往在登录成功后触发)显然是在vue实例化完成之后。axios实例的配置只能在初始化时进行配置,一旦初始化完成就不能更改了。

例如,一个常见的axios挂载操作:

import App from "./App.vue";
import router from "./routers/index";
import store from "./vuex/index";
import {
    
     instance } from "./config/axios";

Vue.prototype.axios = instance;

new Vue({
    
    
  render: h => h(App),
  router,
  store
}).$mount("#app");

上面案例中,在实例化Vue之前,就已经加载了./config/axios.js中的代码,这使得axios实例过早被创建,这时设置的token就只能是浏览器上一次保存的token值,引发bug。

尽管如此,这并不代表我们束手无策,我们需要改进请求头部携带token的处理方式,不再在实例创建的时候设置头部token,而改为请求拦截器设置token,像这样:

import {
    
     getStorageItem } from '@/config/storage';

// instance是axios实例
instance.interceptors.request.use(function (config) {
    
    
    // 在发送请求之前做些什么
    config.header.Authorization =  getStorageItem("token");
    return config;
  }, function (error) {
    
    
    // 对请求错误做些什么
    return Promise.reject(error);
  });

这样每次发送请求时,都会去浏览器storage中重新获取token,因此能够得到最新的token。

快速调用:挂载到Vue原型

你可以将axios实例挂载到Vue的原型上:

Vue.prototype.axios = instance;

这样做的好处是,在vue组件中调用axios时更加方便快速,就像this.$router、this.$store那样:

this.axios.post(url,data).then(()=>{
    
    }).catch(()=>{
    
    })

你无需反复引入axios实例就可以直接调用,是不是轻松愉快些呢!

绕开字符串拼接

详情可参看本人的另一篇文章:axios的使用小技巧:如何绕过字符串拼接,直接传递对象,这里不再赘述。

猜你喜欢

转载自blog.csdn.net/u012443286/article/details/105375347