axios
axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
在前端框架中的应用也是特别广泛,不管是vue还是react,都有很多项目用axios作为网络请求库。
我在最近的几个项目中都有使用axios,并基于axios根据常见的业务场景封装了一个通用的request服务。
业务场景:
1.全局请求配置。
2.get,post,put,delete等请求的promise封装。
3.全局请求状态管理。
4.取消重复请求。
5.路由跳转取消当前页面请求。
6.请求携带token,权限错误统一管理。
默认配置
定义全局的默认配置
axios.defaults.timeout = 10000 //超时取消请求
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
axios.defaults.baseURL = process.env.BASE_URL //挂载在process下的环境常量,在我另一篇文章有详细说明
新创建一个 axios
//-- 新创建一个 axios
let newAxios = axios.create({
//设置请求时是否携带参数
withCredentials:true,
//是即将被发送的自定义请求头
headers: {"Content-Type": "application/json"},
//允许在向服务器发送前,修改请求数据 , 只能用在 'PUT','POST'和 'PATCH',
//后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data) {
return data;
// return qs.stringify(data); // 对 data 进行任意转换处理
}],
paramsSerializer: function(params) { //是一个负责 `params` 序列化的函数
return qs.stringify(params, {arrayFormat: 'brackets'})
},
}),
http request 拦截器-------------------------------------------------
newAxios.interceptors.request.use(
config => {
// 请求次数 ++.
postNum++ ;
// 如果包含日期
if(config.data && config.data.date && config.data.date.length <= 10){
config.data.date = config.data.date.replace(/-/g,'');
}
if (config.url=='research/gsty-fund-audit/unApproveNum') {
//轮询未审批接口不要弹窗
store.commit('upLoading',false);
}else {
store.commit('upLoading',true);
// 如果 loading 没有启动
if(!store.state.loading && !timer){
// 超过三秒 再启动 loading
timer = setInterval(function(){
if(timerNum > 0){
// 显示 loading
store.commit('upLoading',true);
//清空定时器
clearInterval(timer);
timer = null;
timerNum = 0;
}else{
timerNum ++;
}
},300);
}
}
return config;
},
error => {
postNum = 0;
timerNum = 0;
//清空定时器
clearInterval(timer);
// 隐藏 loading
store.commit('upLoading',false);
store.commit('upCommentTip',{msg:error+'<br>请联系管理员',routerPath:'/login'});
return Promise.reject(error)
}
);
http response 拦截器-------------------------
newAxios.interceptors.response.use(
response => {
//得到相应后 请求次数 --
postNum-- ;
//如果有错误信息,则提示
if(response.data.code != 1){
if(response.data.code == -1){
store.commit('upCommentTip',{msg:'您还未登录或您的登录已超时<br>请登录后再访问',routerPath:'/login'});
}else{
let str = response.data.message == 'failed' ?
response.data.data : response.data.message != '' ? response.data.message : response.data.data;
store.commit('showErrorInfo',{type:'fail',msg:str});
}
}
// 如果请求都相应了,则清除定时器
if(postNum == 0){
clearInterval(timer);
timer = null;
// 隐藏 loading
store.commit('upLoading',false);
}
return response;
},
error => {
postNum = 0;
timerNum = 0;
//清空定时器
clearInterval(timer);
// 隐藏 loading
store.commit('upLoading',false);
store.commit('upCommentTip',{msg:error+'<br>请联系管理员',routerPath:'/login'});
return Promise.reject(error)
}
);
get、post、upload、多个方法封装
let httpObj = {
/**
* 封装get方法
* @param url
* @returns {Promise}
*/
axios_get: function (url){
return new Promise((resolve,reject) => {
newAxios.get(url)
.then(
response => {
resolve(response.data);
},
err => {
reject(err)
}
)
.catch(err => {
reject(err)
})
})
},
/**
* 封装post请求
* @param url
* @param data
* @returns {Promise}
*/
axios_post:function (url,params){
//默认同意加 token
if(store.state.userInfo.token != undefined && url != '/login'){
axios.defaults.headers = {
"Content-Type": "application/json",
"loginToken":store.state.userInfo.token
}
}
params = JSON.stringify(params);
return new Promise((resolve,reject) => {
newAxios.post(url,params)
.then(
response => {
resolve(response.data);
},
err => {
reject(err)
}
)
.catch(err => {
reject(err)
})
})
},
/**
* 封装axios_uploader请求
* @param url
* @param data
* @returns {Promise}
*/
axios_uploader:function (url,params,config){
// 创建一个新的 请求
let axiosUploader = axios.create({
//设置请求时是否携带参数
withCredentials:true,
headers: {"Content-Type": "application/x-www-form-urlencoded"},
transformRequest: [function (data) {
return data;
}],
});
//上传,则启用新的请求头
return new Promise((resolve,reject) => {
axiosUploader.post(url,params,config)
.then(
response => {resolve(response.data); },
err => { reject(err) }
)
.catch(err => {
reject(err)
})
})
},
/**
* 封装同时执行多个请求
* @param httpList 是一个对象数组,包含多个请求信息
* @returns {Promise}
*/
axios_all:function(httpList){
let arrHttp = []; //请求数组
for (var obj of httpList) {
if(obj.type == 'get'){
arrHttp.push(axios.get(obj.url));
}else if(obj.type == 'post'){
arrHttp.push(axios_new.post(obj.url,obj.params));
}
}
return new Promise((resolve,reject)=>{
axios.all(arrHttp)
.then(axios.spread(function () {
var tmp = [];
for(var val of arguments){
tmp.push(val.data)
}
resolve(tmp);
}));
})
}
整体代码
import axios from 'axios';
import qs from 'qs';
import store from '@/store'
//-- axios 全局配置
axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? '/api/' : process.env.VUE_APP_HTTP_URL;
//-- 新创建一个 axios
let newAxios = axios.create({
//设置请求时是否携带参数
withCredentials:true,
//是即将被发送的自定义请求头
headers: {"Content-Type": "application/json"},
//允许在向服务器发送前,修改请求数据 , 只能用在 'PUT','POST'和 'PATCH',
//后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data) {
return data;
// return qs.stringify(data); // 对 data 进行任意转换处理
}],
paramsSerializer: function(params) { //是一个负责 `params` 序列化的函数
return qs.stringify(params, {arrayFormat: 'brackets'})
},
}), timer = null, timerNum = 0 , postNum = 0;
//-- http request 拦截器-------------------------------------------------
newAxios.interceptors.request.use(
config => {
// 请求次数 ++.
postNum++ ;
// 如果包含日期
if(config.data && config.data.date && config.data.date.length <= 10){
config.data.date = config.data.date.replace(/-/g,'');
}
if (config.url=='research/gsty-fund-audit/unApproveNum') {
//轮询未审批接口不要弹窗
store.commit('upLoading',false);
}else {
store.commit('upLoading',true);
// 如果 loading 没有启动
if(!store.state.loading && !timer){
// 超过三秒 再启动 loading
timer = setInterval(function(){
if(timerNum > 0){
// 显示 loading
store.commit('upLoading',true);
//清空定时器
clearInterval(timer);
timer = null;
timerNum = 0;
}else{
timerNum ++;
}
},300);
}
}
return config;
},
error => {
postNum = 0;
timerNum = 0;
//清空定时器
clearInterval(timer);
// 隐藏 loading
store.commit('upLoading',false);
store.commit('upCommentTip',{msg:error+'<br>请联系管理员',routerPath:'/login'});
return Promise.reject(error)
}
);
//-- http response 拦截器-------------------------
newAxios.interceptors.response.use(
response => {
//得到相应后 请求次数 --
postNum-- ;
//如果有错误信息,则提示
if(response.data.code != 1){
if(response.data.code == -1){
store.commit('upCommentTip',{msg:'您还未登录或您的登录已超时<br>请登录后再访问',routerPath:'/login'});
}else{
let str = response.data.message == 'failed' ?
response.data.data : response.data.message != '' ? response.data.message : response.data.data;
store.commit('showErrorInfo',{type:'fail',msg:str});
}
}
// 如果请求都相应了,则清除定时器
if(postNum == 0){
clearInterval(timer);
timer = null;
// 隐藏 loading
store.commit('upLoading',false);
}
return response;
},
error => {
postNum = 0;
timerNum = 0;
//清空定时器
clearInterval(timer);
// 隐藏 loading
store.commit('upLoading',false);
store.commit('upCommentTip',{msg:error+'<br>请联系管理员',routerPath:'/login'});
return Promise.reject(error)
}
);
let httpObj = {
/**
* 封装get方法
* @param url
* @returns {Promise}
*/
axios_get: function (url){
return new Promise((resolve,reject) => {
newAxios.get(url)
.then(
response => {
resolve(response.data);
},
err => {
reject(err)
}
)
.catch(err => {
reject(err)
})
})
},
/**
* 封装post请求
* @param url
* @param data
* @returns {Promise}
*/
axios_post:function (url,params){
//默认同意加 token
if(store.state.userInfo.token != undefined && url != '/login'){
axios.defaults.headers = {
"Content-Type": "application/json",
"loginToken":store.state.userInfo.token
}
}
params = JSON.stringify(params);
return new Promise((resolve,reject) => {
newAxios.post(url,params)
.then(
response => {
resolve(response.data);
},
err => {
reject(err)
}
)
.catch(err => {
reject(err)
})
})
},
/**
* 封装axios_uploader请求
* @param url
* @param data
* @returns {Promise}
*/
axios_uploader:function (url,params,config){
// 创建一个新的 请求
let axiosUploader = axios.create({
//设置请求时是否携带参数
withCredentials:true,
headers: {"Content-Type": "application/x-www-form-urlencoded"},
transformRequest: [function (data) {
return data;
}],
});
//上传,则启用新的请求头
return new Promise((resolve,reject) => {
axiosUploader.post(url,params,config)
.then(
response => {resolve(response.data); },
err => { reject(err) }
)
.catch(err => {
reject(err)
})
})
},
/**
* 封装同时执行多个请求
* @param httpList 是一个对象数组,包含多个请求信息
* @returns {Promise}
*/
axios_all:function(httpList){
let arrHttp = []; //请求数组
for (var obj of httpList) {
if(obj.type == 'get'){
arrHttp.push(axios.get(obj.url));
}else if(obj.type == 'post'){
arrHttp.push(axios_new.post(obj.url,obj.params));
}
}
return new Promise((resolve,reject)=>{
axios.all(arrHttp)
.then(axios.spread(function () {
var tmp = [];
for(var val of arguments){
tmp.push(val.data)
}
resolve(tmp);
}));
})
}
}
export default httpObj;
--在main.js 将 axios 改写为 Vue 的原型属性,其他圆形组件也可以使用了
Vue.prototype.$axios_get = http.axios_get;
Vue.prototype.$post = http.axios_post;
Vue.prototype.$uploader = http.axios_uploader;
-在main.js 将
//接口请求地址urls全局引入
import urls from './tools/urls'
新建一个urls文件存放接口
export default {
//用户模块
user: {
loginUser: 'sys/user/loginUser',// 获取用户的登陆信息
findUserPermissions: 'sys/user/findUserPermissions',//获取用户的权限菜单
},
在需要的地方调用接口
getLoginMsg(that) {
that.$post('/sys/user/loginUser').then((res) => {
// console.log(res);
if (res.code == 1) {
// 更新用户信息
that.$store.commit('upUserInfo', res.data);
that.$tools.setCookie('userInfo_cookie',JSON.stringify(res.data));
//获取用户的菜单权限
that.getUserMenu(that, res.data.userId, res.data.username);
}
})
},
网友评论