简介
关于vue中使用axios请求的配置,注意其中区分Vue2.0和Vue3.0的写法。
一、axios配置
由于可能会有多个插件应用,所以有了plugins(utils里面放的是封装的事件处理方法),自行新建相关文件
1.安装axios
npm install axios --save
2.‘plugins/index.js’ 配置
// 导出所有插件
let moduleFiles = require.context('./modules', true, /\.js$/);
export default moduleFiles;
3.环境地址变量配置(axios请求时的服务器地址)
3.1方式一
在项目顶层目录中新建三个文件,分别写入对应的环境配置
.env.development
NODE_ENV = 'production' // 打包模式
outputDir = 'dev' // 要打包到的目录名称
VUE_APP_ENVIRONMENT = 'developmentEnv' // 区分开发环境、测试环境和生产环境的变量
VUE_APP_BASE_API = 'http://xxx.xxx.xxx:8080'
.env.test
NODE_ENV = 'production'
outputDir = 'test'
VUE_APP_ENVIRONMENT = 'testEnv'
VUE_APP_BASE_API = 'https://xxx.xxx.xxx:8081'
.env.production
NODE_ENV = 'production'
outputDir = 'dist'
VUE_APP_ENVIRONMENT = 'productionEnv'
VUE_APP_BASE_API = 'https://xxx.xxx.xxx:8082'
使用
process.env.VUE_APP_BASE_API
3.2方式二
新建一个放在’/public/'目录下的urlConfig.js
文件(当然,其他地方也可以,只是这里可以在打包后进行js文件编辑)
/** 程序/DB版本
* serverType: D-开发, T-测试, P-正式
* java/db: 版本号
*/
window.versions = {
serverType: 'T', // 发布环境
java: '2.20.220430', // 服务器对应的版本号
db: '2.06.220602' // 当前项目的版本号
}
console.log(window.versions)
/* ['后台服务地址', '上传文件地址', '生成文件地址'] */
const AllServerAPI = {
dev: ['http://xxx.xxx.xxx:8080', '', ''],
test: ['https://xxx.xxx.xxx:8081', '', ''],
pro: ['https://xxx.xxx.xxx:8082', '', '']
}
/* 每次只需要修改此处,即可配置对应的请求环境 */
const findAPI = AllServerAPI['dev']
/* 服务器请求地址 */
window.serverAPI = {
baseUrl: findAPI[0],
uploadUrl: findAPI[1],
fileUrl: findAPI[2],
}
使用
// 默认主地址
window.serverAPI.baseUrl
// 注意上传、创建等其他服务的请求时,注意修改axios的请求地址即可
window.serverAPI.uploadUrl
window.serverAPI.fileUrl
4.'axios.js’配置
'use strict';
import axios from 'axios';
// import store from "@/store";
// import { message } from "ant-design-vue"
import { getAllPromise } from '@/utils/tools';
import { triggerEvent } from '@/utils/events';
// 完整配置参考: https://github.com/axios/axios#request-config
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=utf-8';
axios.defaults.headers.put['Content-Type'] = 'application/json;charset=utf-8';
axios.defaults.headers.delete['Content-Type'] =
'application/json;charset=utf-8';
let config = {
// baseURL: window.serverAPI.baseUrl || '', // 此处即在获取请求的服务器地址
baseURL: process.env.VUE_APP_BASE_API || process.env.apiUrl || '', // 此处即在获取请求的服务器地址
timeout: 60 * 1000,
withCredentials: false,
crossDomain: true,
transformRequest: [
(data) => {
if (!data || typeof data === 'string') {
return data;
}
if (data instanceof FormData) {
return data;
}
// 对Blob对象进行处理
let hasBlob = Object.values(data).some((it) => {
return it instanceof Blob;
});
if (!hasBlob) {
return JSON.stringify(data);
}
const formData = new FormData();
Object.entries(data).forEach(([key, value]) => {
formData.append(key, value);
});
return formData;
},
],
};
const _axios = axios.create(config);
// 注册all方法,执行多个并发请求
// 可传入Promise、包含Promise的数组、返回值为Promise的方法
_axios.all = (...requsets) => {
// 获取所有Promise对象
let promiseList = getAllPromise(requsets);
return new Promise((resolve, reject) => {
axios
.all(promiseList)
.then(
axios.spread((...response) => {
// 两个请求现在都执行完成
resolve(response);
})
)
.catch((error) => {
reject(error);
});
});
};
_axios.interceptors.request.use(
(config) => {
// const token = getCookie(AUTH_TOKEN_FRONT);
// config.headers.common[AUTH_TOKEN_END] = token;
const token = 'AUTH_TOKEN_FRONT';
config.headers.common.Token = token;
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 拦截响应
_axios.interceptors.response.use(
(response) => {
// console.log(response)
// 用来判断是否请求成功
const success = response.status === 200;
let messages = '';
if (!success) {
if (typeof response.data === 'string') {
messages = '服务器错误,未获取到响应数据';
} else {
if (response.status === 200) {
return Promise.reject(response);
}
// 请求成功,但在业务上为失败
messages = response.message || response.statusText || '操作执行失败';
}
console.error(messages);
return Promise.reject(response);
}
return {
data: response.data,
success,
messages,
};
},
(error) => {
if (!navigator.onLine) {
triggerEvent(window, 'offline');
return Promise.reject(error);
}
if (!error.response) {
console.error('连接服务器失败');
return Promise.reject(error);
}
let status = error.response.status;
if (status === 401) {
// message.error("您的登录已过期,请重新登录");
// window.location.reload();
// store.dispatch("user/logout");
return Promise.reject(error);
}
if (status < 200) {
console.warning(`未处理的消息响应,状态码:${status}`);
} else if (status >= 300 && status < 400) {
console.warning(`未处理的重定向响应,状态码:${status}`);
} else if (status >= 400 && status < 500) {
console.error(`客户端错误,状态码:${status}`);
} else if (status >= 500) {
console.error(`服务器错误,状态码:${status}`);
}
// 系统请求失败
return Promise.reject(error);
}
);
// -------------------------vue2.x导出-------------------------
// export default {
// install: (Vue) => {
// Vue.$_http = _axios;
// window.$_http = _axios;
// Object.defineProperties(Vue.prototype, {
// $_http: {
// get() {
// return _axios;
// },
// },
// });
// },
// };
// -------------------------vue3.x导出-------------------------
export default {
install: (app) => {
app.$_http = _axios;
window.$_http = _axios;
Object.defineProperties(app.config.globalProperties, {
$_http: {
get() {
return _axios;
},
},
});
},
};
5.'utils/tools.js’配置
/**
* 从参数中获取所有Promise对象,组成数组并返回
* @param {...any} datas 待解析数据
*/
export function getAllPromise(...datas) {
let promiseList = [];
datas.forEach((it) => {
if (isDataType(it, 'Promise')) {
promiseList.push(it);
return;
}
// 是方法则获取执行的结果
if (isDataType(it, 'Function')) {
promiseList.push(...getAllPromise(it()));
return;
}
if (isDataType(it, 'Array')) {
promiseList.push(...getAllPromise(...it));
}
});
return promiseList;
}
/**
* 判断数据的类型是否符合预期
* 只传一个参数data,则返回数据的类型;
* 传入多个参数,则判断数据是否属于该类型(或属于类型数组中的一个)
* @param {*} data 需要判断类型的数据
* @param {...any} typeList 字符串或字符串数组,可不传
*/
export function isDataType(data, ...typeList) {
let dataType = Object.prototype.toString
.call(data)
.replace(/^\[object/, '')
.replace(/\]$/, '')
.replace(/\s/, '');
typeList = flat(typeList);
let hasType = typeList.some((it) => {
return it && isDataType(it) === 'String';
});
if (!hasType) {
return dataType;
}
if (
typeList.includes(dataType) ||
typeList.includes(dataType.toLowerCase())
) {
return true;
}
return false;
}
/**
* Array.flat在app和Trident内核上会报错,重写
* @param {Array} list 目标数组
*/
export function flat(list) {
if (Array.prototype.flat) {
return list.flat(Infinity);
}
let retArr = [];
if (!Array.isArray(list)) {
throw new Error(
`Invalid parameter: type check failed for parameter 'list'. Expected Array, But got ${typeof list} with value ${list}`
);
}
list.forEach((it) => {
if (!Array.isArray(it)) {
retArr.push(it);
return;
}
retArr.push(...flat(it));
});
return retArr;
}
6.'utils/events.js’配置
// 浏览器中的事件管理
/**
* 触发一个DOM事件
* @param {Element} node 事件发生的节点元素
* @param {String} name 事件名称,不含前缀:on
* @param {...any} options 可选的事件配置项
*/
export function triggerEvent(node, name, ...options) {
if (node.fireEvent) {
return node.fireEvent('on' + name);
}
let eventName;
let evt;
if (/^mouse|click/.test(name)) {
eventName = 'MouseEvents';
evt = document.createEvent(eventName);
evt.initMouseEvent(name, ...options);
} else if (['DOMActivate', 'DOMFocusIn', 'DOMFocusOut'].includes(name)) {
eventName = 'UIEvents';
evt = document.createEvent(eventName);
evt.initUIEvent(name, ...options);
} else if (/^key/.test(name)) {
eventName = 'KeyboardEvent';
evt = document.createEvent(eventName);
evt.initKeyboardEvent(name, ...options);
} else if (name.startsWith('DOM')) {
eventName = 'MutationEvents';
evt = document.createEvent(eventName);
evt.initMutationEvent(name, ...options);
} else {
eventName = 'HTMLEvents';
evt = document.createEvent(eventName);
evt.initEvent(name, ...options);
}
return node.dispatchEvent(evt);
}
二、请求接口路径api配置
自行根据目录结构新建文件。
方便区分接口所属模块,于是根据接口分类进行新建js文件。
1. api集合中心(‘api/index.js’)
'use strict';
/* eslint-disable no-unused-vars */
/** 有几个模块,subList就有几个元素
* @param: name 子系统名称
* @param: url 子系统使用的环境变量(请求地址,便于不同模块请求不同服务器的配置,可在三个环境中新增类似VUE_APP_BASE_API的域名地址变量)
*/
const subList = [
{
name: 'API_LIST_USER',
url: 'VUE_APP_BASE_API',
},
{
name: 'API_LIST_MANAGEMENT',
url: 'VUE_APP_BASE_API',
},
];
// 所有api子系统
let API_LIST = {};
const moduleFiles = require.context('./modules', true, /\.js$/);
moduleFiles.keys().forEach((modulePath) => {
API_LIST = { ...API_LIST, ...moduleFiles(modulePath).default };
});
// 合成API地址集合
let apiList = {};
subList.forEach((it) => {
let subApi = Object.entries(API_LIST[it.name]).reduce(
(target, [key, value]) => {
target[key] = process.env[it.url].replace(/\W*$/, '') + '/' + value.replace(/^\W*/, '');
return target;
},
{}
);
apiList = { ...apiList, ...subApi };
});
export default apiList;
2. 模块分类一:user(‘api/user.js’)
/* 用户相关api */
export default {
API_LIST_USER: {
INTERFACE_GET_USER_LOGIN: 'user/login',
INTERFACE_GET_USER_LIST: 'admin/users'
},
};
3. 模块分类二:管理(‘api/management.js’)
/* 管理相关api
* @param: key => 子系统名称,用于api/index.js中
*/
export default {
API_LIST_MANAGEMENT: {
INTERFACE_GET_ENGINEERINGWORK_LIST: '/engineertype',
INTERFACE_POST_ENGINEERINGWORK_CREATE: '/admin/engineertype/create',
INTERFACE_DELETE_ENGINEERINGWORK_DELETE: '/admin/engineertype/{engineertypeid}',
},
};
三、axios和接口api的全局注入
(1)vue2.x
import Vue from 'vue';
import App from './App.vue';
// 注册自定义插件
import moduleFiles from './plugins';
// 引入api地址
import apiList from '@/api';
// 批量使用自定义插件
moduleFiles.keys().forEach(modulePath => {
Vue.use(moduleFiles(modulePath).default);
});
// 注册所有api地址为全局变量
Vue.prototype.$_API = apiList;
new Vue({
render: (h) => h(App),
}).$mount('#app');
(2)vue3.x
import { createApp } from 'vue';
import App from './App.vue';
// 引入自定义插件
import moduleFiles from './plugins';
// 引入api地址
import apiList from '@/api';
const app = createApp(App);
app.mount('#app');
// 注册所有api地址为全局变量
app.config.globalProperties.$_API = apiList;
// 批量使用自定义插件
moduleFiles.keys().forEach((modulePath) => {
app.use(moduleFiles(modulePath).default);
});
四、请求接口的使用方式
以下是vue2.x的使用方式
// 其中 url为接口地址,在api目录下定义
// config内容为参数和其他配置,例如:
--------------------------执行 GET 请求---------------------------------
// 执行 GET 请求
this.$_http.get('url' + "?ID=12345")
.then(response => {
// 自己的操作
console.log(response);
})
// 不需要写catch,axios配置会自动提示出来
// 可选地,上面的请求可以这样写
this.$_http.get('url', {
params: {
ID: 12345
}
}).then(response => {
// 自己的操作
console.log(response);
})
--------------------------执行 POST 请求---------------------------------
// 执行 POST 请求
this.$_http.post('url', {
firstName: "Fred",
lastName: "Flintstone"
}).then(response => {
// 自己的操作
console.log(response);
})
--------------------------执行 DELETE 请求---------------------------------
// 执行 POST 请求
this.$_http.delete('url', {
data: { id: 1 }
}).then(response => {
// 自己的操作
console.log(response);
})
--------------------------案例---------------------------------------------
let params = {
page: 0,
size: 10,
};
this.$_http.get(this.$_API.INTERFACE_GET_USER_LIST, { params }).then((res) => {
console.log(res);
});
以下是vue3.x的使用方式
import { getCurrentInstance } from "vue"
setUp() {
// 方式一
// const internalInstance = getCurrentInstance()
// const globalProperties = internalInstance.appContext.config.globalProperties
// const _http = globalProperties.$_http
// const _API = globalProperties.$_API
// 方式二
const { proxy } = getCurrentInstance()
const _http = proxy.$_http
const _API = proxy.$_API
console.log(_http, _API)
let params = {
page: 0,
size: 10,
}
_http.get(_API.INTERFACE_GET_USER_LIST, { params }).then((res) => {
console.log("axios请求结果", res);
})
}
注意
在 axios.js 中,关于 console.error 相关的部分,替换为自己项目所引入的ui框架的消息提示即可,如 ant Design 的 message,就有请求后报错的相关提示。
最后
觉得有用的朋友请用你的金手指点一下赞,或者评论留言一起探讨技术!