本文详细介绍在Vue项目中如何规范封装axios,包括基础配置、接口分层管理及拦截器的使用。重点讲解如何通过拦截器判断并处理特定请求,以及如何利用Promise.all或axios.all实现多个并发请求的加载状态控制,附带跨域处理与POST序列化建议。
Axios简介与特性
Axios是一个基于Promise的HTTP客户端,既适用于浏览器环境,也支持Node.js运行环境。自Vue 2.0发布后,官方不再维护vue-resource,转而推荐使用axios,因此本项目采用axios作为网络请求库。其主要功能特性包括:在浏览器中发送XMLHttpRequests请求,在Node.js中发送http请求,支持Promise API,提供请求和响应的拦截机制,支持请求和响应数据的转换,支持取消请求,自动将JSON数据转换为JavaScript对象,以及客户端自动防护免受CSRF/XSRF(跨站请求伪造)攻击。
Axios封装与目录结构
封装使用策略
建议将代码拆分为三个独立文件以优化结构。
目录结构建议如下:在src目录下创建service文件夹,其中包含axios.js(负责axios配置、拦截器及统一url处理)、index.js(定义接口方法,调用api模块,供页面级组件调用);在api文件夹下创建index.js(定义具体API方法,调用后端提供的接口,供service层的接口方法调用)。
基础配置与接口调用
axios.js基本配置
'use strict';
import axios from 'axios';
// 自动识别接口使用开发环境地址(开发环境地址做了 proxyTable 代理,故设置为空)或线上地址
axios.defaults.baseURL = process.env.NODE_ENV === 'production' ? process.env.API_ROOT : '';
// 开发环境直接打包测试
// axios.defaults.baseURL = '';
axios.interceptors.request.use(config => {
return config;
}, error => {
console.log(error);
return Promise.reject(error);
});
axios.interceptors.response.use(res => {
const apiRes = res.data;
return apiRes;
}, async error => {
console.dir(error);
return Promise.reject(error);
});
export default axios;
api/index.js 调用后端提供的接口
import Ax from '@/service/axios';
import qs from 'qs';
export default {
fetchBlog (reqData) {
return Ax.get('/krryblog/blog/getBlog', {params: reqData});
},
addBlog (reqData) {
return Ax.post('/krryblog/blog/addBlog', qs.stringify(reqData));
},
updateBlog (reqData) {
return Ax.post('/krryblog/blog/updateBlog', qs.stringify(reqData));
},
deleteBlogCover (id, reqData) {
return Ax.post(`/krryblog/blog/deleteBlogCover/${id}`, qs.stringify(reqData));
},
};
index.js接口方法(调用api)
import Api from './api';
export async function getBlog(reqData) {
let res = await Api.fetchBlog(reqData);
return res;
},
export async function addBlog (reqData) {
let res = await Api.addBlog(reqData);
return res;
},
export async function updateBlog (reqData) {
let res = await Api.updateBlog(reqData);
return res;
},
export async function deleteBlogCover (id, reqData) {
let res = await Api.deleteBlogCover(id, reqData);
return res;
},
页面调用示例
完成上述配置后,即可在页面组件中直接调用封装好的接口方法。
import { getBlog } from '@/service'
export default {
data() {
return {
tableData: [],
pageIndex: 1,
pageSize: 9
}
},
created() {
this.getList();
},
methods: {
async getList() {
let { result } = await getBlog({
pageIndex: this.pageIndex,
pageSize: this.pageSize
});
this.tableData = result.data;
},
}
并发请求处理
接下来介绍如何在axios中执行多个并发请求。
async getList() {
let resArr = []
for (let val of this.arrId) {
// push 请求
resArr.push(queryPropertyValue({ id: val }))
}
this.tableData = []
Promise.all(resArr).then(res => {
for (let val of res) {
let vals = val.result.propertyValues
// 每个请求的结果 push 到 tableData
vals.forEach(item => this.tableData.push(item))
}
})
},
或者直接在axios代码中编写Promise.all逻辑。
// 根据 id 获取某一条商品数据
let getDetail = (id)=>{
return axios.get(`/detail?bid=${id}`);
}
// 检测登录的用户是否将此商品加入购物车
let detectCar = (shopId,userId)=>{
return axios.get(`/detectCar?shopId=${shopId}&userId=${userId}`);
}
// 获取一条商品数据、并且检测是否加入购物车
let getDeAll = (shopId,userId)=>{
axios.all([
getDetail(shopId),
detectCar(shopId,userId)
]).then(axios.spread((resDetail, resCar)=>{
// 两个请求现已完成
// 打印两个请求的响应值
console.log(resDetail);
console.log(resCar);
}));
}
以下是axios实例方法的说明。
axios#request(config)
axios#get(url [,config])
axios#delete(url [,config])
axios#head(url [,config])
axios#post(url [,data [,config]])
axios#put(url [,data [,config]])
axios#patch(url [,data [,config]])
关于请求配置:url是必需参数,若未指定method,请求将默认为GET。
拦截器与特定请求处理
axios拦截特定请求的处理方式
业务场景中常遇到需要拦截某些特定请求的情况,以便在这些特定请求发生时,页面采取或不采取相应的变化。
研究axios的request统一拦截方法:axios.interceptors.request.use(function (config) {})
拦截器接收的参数config结构如下:
通过观察config.url可以发现,它即为请求接口的地址。例如,若URL为“/getClassify”,则“getClassify”即为该请求的方法名。因此,可以通过解析字符串来判断是否为特定请求,从而执行相应的逻辑变化。
axios.interceptors.request.use(config => {
// 判断请求是否是 getClassify,如果是 getClassify,不加载 LoadingBar
let url = config.url;
if (url.split('/').pop() === 'getClassify') {
flag = false;
} else {
iView.LoadingBar.start();
flag = true;
}
return config;
}, error => {
console.log(error);
return Promise.reject(error);
});
请求加载状态与Post问题
如何判断所有请求加载完毕
let reqNum = 0
axios.interceptors.request.use(function (config) {
// 在请求发出之前进行一些操作,每次发出请求就 reqNum++
reqNum++
_bus.$emit('showloading')
return config
}
axios.interceptors.response.use(response => {
// 接受请求后 reqNum--,判断请求所有请求是否完成
reqNum--
if (reqNum <= 0) {
_bus.$emit('closeLoading')
} else {
_bus.$emit('showloading')
}
})
关于axios的post请求相关问题
如果遇到post请求的跨域问题,可以在webpack配置文件中设置proxyTable来处理跨域。参考链接:https://ainyi.com/27。此外,post请求携带参数时,需要进行序列化操作,使用qs.stringify(reqData)处理数据。
saveNormalAds (reqData) {
return Ax.post('/index.php?krry', qs.stringify(reqData));
},
总结
以上介绍了在Vue项目中详解axios的封装使用、拦截特定请求以及判断所有请求加载完毕的方法,希望对大家有所帮助。如有任何疑问,欢迎留言,作者会及时回复。