关于前端:工作中axios的二次封装与要点备忘

1次阅读

共计 4590 个字符,预计需要花费 12 分钟才能阅读完成。

一、axios 是什么

  axios 是一个轻量的 HTTP 客户端。

  基于 XMLHttpRequest 服务来执行 HTTP 申请,反对丰盛的配置,反对 Promise,反对浏览器端和 Node.js 端。自 Vue2.0 起,尤大发表勾销对 vue-resource 的官网举荐,转而举荐 axios。当初 axios 曾经成为大部分 Vue 开发者的首选。

个性

  • 从浏览器中创立 XMLHttpRequests
  • node.js 创立 http 申请
  • 反对 Promise API
  • 拦挡申请和响应
  • 转换申请数据和响应数据
  • 勾销申请
  • 主动转换 JSON 数据
  • 客户端反对进攻 XSRF

二、axios 的二次封装

  axiosAPI 很敌对,能够很轻松地在我的项目中间接应用。不过随着我的项目规模增大,如果每发动一次 HTTP 申请,就要把这些比方设置超时工夫、设置申请头、依据我的项目环境判断应用哪个申请地址、错误处理等等操作,都须要写一遍。这种重复劳动不仅浪费时间,而且让代码变得冗余不堪,难以保护。为了进步代码品质,咱们应该在我的项目中二次封装一下 axios 再应用。

1. 如何封装

封装的同时,你须要和后端协商好一些约定,申请头,状态码,申请超时工夫 …….

  • 设置接口申请前缀:依据开发、测试、生产环境的不同,前缀须要加以辨别
  • 申请头 : 来实现一些具体的业务,必须携带一些参数才能够申请(例如:会员业务)
  • 状态码: 依据接口返回的不同 status,来执行不同的业务,这块须要和后端约定好
  • 申请办法:依据 get、post 等办法进行一个再次封装,应用起来更为不便
  • 申请拦截器: 依据申请的申请头设定,来决定哪些申请能够拜访
  • 响应拦截器:这块就是依据 后端返回来的状态码断定执行不同业务

axios 的罕用根本配置项为:

axios({
  method: 'get', // post、get、put、delete....
  baseURL: '', // 申请的域名,根本地址,公共的门路
  url: '', // 申请的门路
  params: {}, // get 参数会将申请参数拼接在 url 上
  data: {}, // post 会将申请参数放在申请体中
  headers: {}, // 设置申请头,例如设置 token 等
  timeout: 1000, // 设置申请超时时长,单位:ms
  withCredentials:default,// 表明了是否是跨域申请、默认是 default
  maxContentLength:1000// 相应内容的最大值
})

在我的项目中,我是这样二次封装的:

1. 在 axios.js 文件内设置好根底的配置项:

import Vue from "vue";
import axios from "axios";

axios.defaults.timeout = 100000;
axios.defaults.withCredentials = true;
Vue.prototype.$axios = axios;// 把 axios 挂载到 vue 的原型上供全局调用。

2. 如果有生产环境的辨别,则能够通过判断 node 环境变量确定链接申请地址的baseURL

if (process.env.NODE_ENV === 'development') {axios.defaults.baseURL = 'http://dev.xxx.com'} else if (process.env.NODE_ENV === 'production') {axios.defaults.baseURL = 'http://prod.xxx.com'}

3. 而后,须要增加申请拦截器和响应拦截器:

a. 申请拦截器能够在每个申请里加上token,或者增加一些其余默认须要发送给后端的根底信息。

以下是申请拦截器的简略用法示例:

// 申请拦截器
axios.interceptors.request.use(
  config => {
    // 每次发送申请之前判断是否存在 token
    // 如果存在,则对立在 http 申请的 header 都加上 token,这样后盾依据 token 判断你的登录状况,此处 token 个别是用户实现登录后贮存到 localstorage 里的,上面的代码只是一个简略示意
    token && (config.headers.Authorization = token)
    return config
  },
  error => {return Promise.error(error)
  })

  进阶的做法,就是存储每次发送的申请,拦挡勾销之前曾经发送然而还没收到后端回应的雷同申请,或者 router(路由)跳转前清除掉上一个router 里暂未收到后端回应的申请。
  说到这个问题,就须要讲到 axioscancelToken这个 API,该API 能够获取到以后申请造成勾销对应申请的函数,调用后即勾销该申请。

对应的代码如下所示:

const CancelToken = axios.CancelToken;
import store from 'store.js'
Vue.$pending = {}

axios.interceptors.request.use((config) => {
  let key = config.url + '&' + config.method;// 通过对应字段组成可惟一确定勾销申请函数的 key
  removePending(key, true)// 删除雷同的申请
  //
  config.cancelToken = new CancelToken(cancelFun => { // cancelFun => 勾销函数的形参 实际上对应的是这个勾销函数
    // 一个申请的勾销函数 对应着一次申请
    // 执行勾销函数 能力勾销本次申请 存储本次申请对应的勾销函数 保障每次申请是惟一的 这样能力判断是否存在反复申请
    Vue.$pending[key] = cancelFun
  })
  // 增加一些默认的参数,具体视我的项目决定
  addDefaultParams(config.headers, store)
  return config
})

addDefaultParams(obj, store){// 增加一些默认的参数,具体视我的项目决定}

function removePending(key, isRequest = false) {if (Vue.$pending[key]) {// 当上一次申请未响应式 再一次发送申请时 会把上一次申请中断掉 并把本次自定义错误信息 放入 reject(err)中
    Vue.$pending[key]()// 勾销反复的申请,不须要函数参数
    delete Vue.$pending[key]// 被勾销申请后,删除掉该勾销函数
  }
}

b. 响应拦截器能够在接管到响应后先做一层操作,如依据状态码判断登录状态是否须要返回登录页面、受权。

axios.interceptors.response.use(response => {
  // 如果返回的状态码为 200,阐明接口申请胜利,能够失常拿到数据
  // 否则的话抛出谬误
  if (response.status === 200) {if (response.data.code === 511) {// 未受权调取受权接口} else if (response.data.code === 510) {// 未登录跳转登录页} else {return Promise.resolve(response)
    }
  } else {return Promise.reject(response)
  }
}, error => {
  // 咱们能够在这里对异样状态作对立解决
  if (error.response.status) {
    // 解决申请失败的状况
    // 对不同返回码对相应解决
    return Promise.reject(error.response)
  }
})

我的项目里的响应拦截器代码如下:

axios.interceptors.response.use((response) => {
  let key = response.config.url + '&' + response.config.method
  removePending 函数(key)// 删除雷同的申请
  if (!response) {return false;}
  if (response.request.responseType === 'blob') {return response}
  return response.data;
},
  (content) => {if(content?.response?.status==="401"){checkToken();
    }
    return Promise.reject(content);
  }
);

function checkToken(){    
  // 查看 localStorage 内是否有 tokenId,若没有,则 store 设置为 logout,路由跳转到登录界面
  if(!localStorage.getItem("tokenId")){store.dispatch('logout');
    router.push({name: "login"});
  }
  else{
    // 若 localStorage 内有 tokenId,则登录状态过期,函数内代码性能可为弹出从新登录小窗口
    debounceUnauthorized();}
}

  当须要实现路由跳转前勾销反复申请,则在 main.js 文件,即 router 文件,在其 beforeEach 钩子函数内写入 removePending 函数来删除申请。

router.beforeEach((to, from, next) => {for(let key in Vue.$pending){Vue.$pending[key]();// 顺次删除 pending 申请}
  Vue.$pending = {};
  .......... 这上面是你的路由验证代码..........
})

  以上是 axios 的根本配置,接着,对于我的项目里每一个包或者模块,都会有本人的 axios 申请汇合的 js 文件。通过上一步把 axios 挂载到 vue 上,其余 js 文件能够通过 this.$axios 来调用 axios 插件。举个例子如下:

//demo.js
export default{createPo: (param) => {return $axios.$post('url', {param});
  },
  .......... 文件..........
}

  像下面的文件,每隔包或者模块都会有一个对应的文件来存储,能够将他们搁置在同一个文件夹内,不便获取。比如说,所有的申请文件都放在同级的 modules 文件夹,那获取相干的内容,能够通过以下形式:

import Vue from "vue";

const modulesFiles = require.context("./modules", true, /\.js$/);
const modules = {};
modulesFiles.keys().map((key) => {const keys = key.replace(/(\.\/|\.js)/g, "");
  modules[keys.split("/").pop()] = modulesFiles(key).default;
});
Vue.prototype.$api = modules;

export default {modules}

通过以上的设置,在其余 vue 文件内就能够通过 this.$api.$demo.createPo 间接调用申请函数了。
至此,axios的二次封装根本完结(后续有什么其余设置再来补充)

三、axios 的调用形式备忘

正文完
 0