跳转到主内容
极星编程网:以代码为星,赴技术山海!

解析vue中axios的封装请求(附步骤代码)

一、简介 axios 是一个轻量的http客户端,它基于
xmlhttprequest
服务来执行 http 请求,支持丰富的配置,支持 promise,支持浏览器端和 node.js 端。自 vue 2.0起,尤大大宣布取消对
vue-resource
的官方推荐,转而推荐 axios。现在 axios 已经成为大部分 vue 开发者的首选。( 如果你还不熟悉 axios,可以在这里查看它的api。)【相关推荐: vue.js视频教程 】 封装前,先来看下,不封装的情况下,一个实际项目中axios请求的样子。 大概是长这样:
axios('http://localhost:3000/data', { method: 'GET', timeout: 1000, withCredentials: true, headers: { 'Content-Type': 'application/json', Authorization: 'xxx', }, transformRequest: [function (data, headers) { return data; }], // 其他请求配置... }) .then((data) => { // todo: 真正业务逻辑代码 console.log(data); }, (err) => { if (err.response.status === 401) { // handle authorization error } if (err.response.status === 403) { // handle server forbidden error } // 其他错误处理..... console.log(err); });
可以看到在这段代码中,页面代码逻辑只在第15行处,上方的一大块请求配置代码和下方一大块响应错误处理代码,几乎跟页面功能没有关系,而且每个请求中这些内容都差不多,甚至有的部分完全一样。 二、封装后 1.封装步骤 立即学习 “ 前端免费学习笔记(深入) ”; 封装的本质就是在待封装的内容外面添加各种东西,然后把它们作为一个新的整体呈现给使用者,以达到扩展和易用的目的。 封装
axios
要做的事情,就是把所有HTTP请求共用的配置,事先都在axios上配置好,预留好必要的参数和接口,然后把它作为新的axios返回。 目录结构如下(由Vue-cli 3.0 生成): |--public/|--mock/|   |--db.json  # 我新建的接口模拟数据|--src/|   |--assets/|   |--components/|   |--router/|   |--store/|   |--views/|       |--Home.Vue|   |--App.vue|   |--main.js|   |--theme.styl|--package.json|... 2.封装目标 在 Home 页,发起 axios 请求时就像调用一个只有少量参数的方法一样简单,这样我就可以专注业务代码了。 1. 将 axios 封装到一个独立的文件 在src下创建 utils/http.js 文件
cd src mkdir utils touch http.js
引入 axios
// src/utils/http.js import axios from 'axios';
创建一个类
//src/utils/http.js //... class NewAxios { }
给不同环境配置不同请求地址 根据
process.env.NODE_ENV
配置不同的
baseURL
,使项目只需执行相应打包命令,就可以在不同环境中自动切换请求主机地址。
// src/utils/http.js //... const getBaseUrl = (env) => { let base = { production: '/', development: 'http://localhost:3000', test: 'http://localhost:3001', }[env]; if (!base) { base = '/'; } return base; }; class NewAxios { constructor() { this.baseURL = getBaseUrl(process.env.NODE_ENV); } }
配置超时时间
timeout
属性,我一般设置10秒。
// src/utils/http.js //... class NewAxios { constructor() { //... this.timeout = 10000; } }
配置允许携带凭证
widthCredentials
属性设为
true
// src/utils/http.js //... class NewAxios { constructor() { //... this.withCredentials = true; } }
给这个类创建实例上的方法request 在
request
方法里,创建新的axios实例,接收请求配置参数,处理参数,添加配置,返回axios实例的请求结果(一个promise对象)。 你也可以不创建,直接使用默认导出的axios实例,然后把所有配置都放到它上面,不过这样一来整个项目就会共用一个axios实例。虽然大部分项目下这样够用没问题,但是有的项目中不同服务地址的请求和响应结构可能完全不同,这个时候共用一个实例就没办法支持了。所以为了封装可以更通用,更具灵活性,我会使用
axios
的
create
方法,使每次发请求都是新的axios实例。
// src/utils/http.js //... class NewAxios { //... request(options) { // 每次请求都会创建新的axios实例。 const instance = axios.create(); const config = { // 将用户传过来的参数与公共配置合并。 ...options, baseURL: this.baseURL, timeout: this.timeout, withCredentials: this.withCredentials, }; // 配置拦截器,支持根据不同url配置不同的拦截器。 this.setInterceptors(instance, options.url); return instance(config); // 返回axios实例的执行结果 } }
因为拦截器配置内容比较多,所以封装成一个内部函数了。 Vue-router参考手册 Vue-router参考手册下载 下载 配置请求拦截器 在发送请求前对请求参数做的所有修改都在这里统一配置。比如统一添加token凭证、统一设置语言、统一设置内容类型、指定数据格式等等。做完后记得返回这个配置,否则整个请求不会进行。 我这里就配置一个
token
。
// src/utils/http.js //... class NewAxios { //... // 这里的url可供你针对需要特殊处理的接口路径设置不同拦截器。 setInterceptors = (instance, url) => { instance.interceptors.request.use((config) => { // 请求拦截器 // 配置token config.headers.AuthorizationToken = localStorage.getItem('AuthorizationToken') || ''; return config; }, err => Promise.reject(err)); } //... }
配置响应拦截器 在请求的
then
或
catch
处理前对响应数据进行一轮预先处理。比如过滤响应数据,更多的,是在这里对各种响应错误码进行统一错误处理,还有断网处理等等。 我这里就判断一下403和断网。
// src/utils/http.js //... class NewAxios { //... setInterceptors = (instance, url) => { //... instance.interceptors.response.use((response) => { // 响应拦截器 // todo: 想根据业务需要,对响应结果预先处理的,都放在这里 console.log(); return response; }, (err) => { if (err.response) { // 响应错误码处理 switch (err.response.status) { case '403': // todo: handler server forbidden error break; // todo: handler other status code default: break; } return Promise.reject(err.response); } if (!window.navigator.online) { // 断网处理 // todo: jump to offline page return -1; } return Promise.reject(err); }); } //... }
另外,在拦截器里,还适合放置loading等缓冲效果: 在请求拦截器里显示loading,在响应拦截器里移除loading。这样所有请求就都有了一个统一的
loading
效果。 默认导出新的实例
// src/utils/http.js //... export default new NewAxios();
最后完整的代码如下:
// src/utils/http.js import axios from 'axios'; const getBaseUrl = (env) => { let base = { production: '/', development: 'http://localhost:3000', test: 'http://localhost:3001', }[env]; if (!base) { base = '/'; } return base; }; class NewAxios { constructor() { this.baseURL = getBaseUrl(process.env.NODE_ENV); this.timeout = 10000; this.withCredentials = true; } // 这里的url可供你针对需要特殊处理的接口路径设置不同拦截器。 setInterceptors = (instance, url) => { instance.interceptors.request.use((config) => { // 在这里添加loading // 配置token config.headers.AuthorizationToken = localStorage.getItem('AuthorizationToken') || ''; return config; }, err => Promise.reject(err)); instance.interceptors.response.use((response) => { // 在这里移除loading // todo: 想根据业务需要,对响应结果预先处理的,都放在这里 return response; }, (err) => { if (err.response) { // 响应错误码处理 switch (err.response.status) { case '403': // todo: handler server forbidden error break; // todo: handler other status code default: break; } return Promise.reject(err.response); } if (!window.navigator.online) { // 断网处理 // todo: jump to offline page return -1; } return Promise.reject(err); }); } request(options) { // 每次请求都会创建新的axios实例。 const instance = axios.create(); const config = { // 将用户传过来的参数与公共配置合并。 ...options, baseURL: this.baseURL, timeout: this.timeout, withCredentials: this.withCredentials, }; // 配置拦截器,支持根据不同url配置不同的拦截器。 this.setInterceptors(instance, options.url); return instance(config); // 返回axios实例的执行结果 } } export default new NewAxios();
现在
axios
封装算是完成了80%。我们还需要再进一步把axios和接口结合再封装一层,才能达到我在一开始定的封装目标。 3. 使用新的 axios 封装API 在 src 目录下新建 api 文件夹。把所有涉及HTTP请求的接口统一集中到这个目录来管理。 新建
home.js
。我们需要把接口根据一定规则分好类,一类接口对应一个js文件。这个分类可以是按页面来划分,或者按模块等等。为了演示更直观,我这里就按页面来划分了。实际根据自己的需求来定。 使用新的 axios 封装API(固定url的值,合并用户传过来的参数),然后命名导出这些函数。
// src/api/home.js import axios from '@/utils/http'; export const fetchData = options => axios.request({ ...options, url: '/data', }); export default {};
在 api 目录下新建 index.js,把其他文件的接口都在这个文件里汇总导出。
// src/api/index.js export * from './home';
这层封装将我们的新的axios封装到了更简洁更语义化的接口方法中。 现在我们的目录结构长这样: |--public/ |--mock/ |   |--db.json  # 接口模拟数据 |--src/ |   |--api/     # 所有的接口都集中在这个目录下 |       |--home.js  # Home页面里涉及到的接口封装在这里 |       |--index.js # 项目中所有接口调用的入口 |   |--assets/ |   |--components/ |   |--router/ |   |--store/ |   |--utils/ |       |--http.js  # axios封装在这里 |   |--views/ |       |--Home.Vue |   |--App.vue |   |--main.js |   |--theme.styl |--package.json |... 4.使用封装后的axios 现在我们要发HTTP请求时,只需引入 api 下的 index.js 文件就可以调用任何接口了,并且用的是封装后的 axios。
// src/views/Home.vue
axios请求被封装在fetchData函数里,页面请求压根不需要出现任何axios API,悄无声息地发起请求获取响应,就像在调用一个简单的 Promise 函数一样轻松。并且在页面中只需专注处理业务功能,不用被其他事物干扰。

相关文章