为了方便项目的维护,以及规范性,对axios进行必要的封装
一、在 utils目录下 创建 auth.js 请求头 token的封装
import Cookies from 'js-cookie'
const TokenKey = 'loginToken'
// 获取token
export function getToken() {
return Cookies.get(TokenKey)
}
// 创建token
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
// 删除token
export function removeToken() {
return Cookies.remove(TokenKey)
}
二、 在api目录下面新建文件api-config.js
import axios from 'axios';
import { Message } from 'element-ui'; // 用于错误提示
import store from '../store'; // token存储在 store
import { getToken } from '@/utils/auth'; // 请求头 token 的封装
import * as _config from '@/config/http.config'; // 请求头的基础数据 如 baseUrl 等
import Router from '@/router'; // 做路由跳转,如登录失效 跳转登录页面
// 创建基础的 请求参数
let baseOptios = {
baseURL: _config.baseUrl, // api的base_url 默认的请求接口前缀
timeout: 50000, // 请求超时时间
retry: 1, // 请求次数
retryDelay: 1000, // 请求间隔
withCredentials: false // 是否可以携带cookies
}
// 创建axios实例
const Axios = axios.create(baseOptios);
// request请求数据拦截器
Axios.interceptors.request.use(
config => {
if (store.getters.token) {
if (!config.url.includes('http://')) {
config.headers['Authorization'] = getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
}
}
// return config
return Promise.resolve(config);
},
error => {
// Do something with request error
console.warn('----------------------------------------> ' + (new Date()))
console.error('请求超时!')
console.error('request error:>', error)
console.warn('----------------------------------------------------------------------------------------')
Promise.reject(error);
}
);
// 响应http状态码 跟后端定义好
const codeMessage = {
200: '服务器成功返回请求的数据。',
201: '新建或修改数据成功。',
202: '一个请求已经进入后台排队(异步任务)。',
204: '删除数据成功。',
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
401: '用户没有权限(令牌、用户名、密码错误)。',
403: '用户得到授权,但是访问是被禁止的。',
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
406: '请求的格式不可得。',
408: '请求超时。',
410: '请求的资源被永久删除,且不会再得到的。',
422: '当创建一个对象时,发生一个验证错误。',
500: '服务器发生错误,请检查服务器。(服务器内部错误)',
501: '服务未实现。',
502: '网关错误。',
503: '服务不可用,服务器暂时过载或维护。',
504: '网关超时。',
505: 'HTTP版本不受支持。'
}
// respone响应拦截器
Axios.interceptors.response.use(
response => {
const { status, message } = response.data;
if (status !== 200) { // 请求不是成功的 跟后端统一定义好,并且接口都按这个规范来
console.warn('----------------------------------------> ' + (new Date()))
console.warn('request url:>', response.config.url || response.request.path || '')
console.warn('request param:>', response.config.data || '')
console.warn('response server status:>', data.status || '')
console.warn('response server message:>', data.message || '')
console.warn('----------------------------------------------------------------------------------------')
// 显示提示信息
Message({
type: 'error',
message: `${message}`
});
}
// ?一层一层去找对应的数据 需要跟后端统一定义好
return Promise.resolve(response.data?.data ?? response);
// return Promise.reject(response);
},
function axiosRetryInterceptor (error) {
const config = error.config;
// If config does not exist or the retry option is not set, reject
if (!config || !config.retry) {
Message({
type: 'error',
message: `请求服务好像出错了:${codeMessage[status]}`
});
return Promise.reject(error);
}
// 获取请求的次数
config.__retryCount = config.__retryCount || 0;
// Check if we've maxed out the total number of retries
const status = error?.response?.status;
if (status === 401) { //登录失效
Message({
type: 'error',
message: `${codeMessage[status]}`
});
Router.push('/login');
// Reject with the error
return Promise.reject(error);
} else if (config.__retryCount >= config.retry) { // 请求次数大于等于设置请求次数时
Message({
type: 'error',
message: `${codeMessage[status]}`
});
// Reject with the error
return Promise.reject(error);
}
config.__retryCount += 1;
// 设置请求间隔时间方法
const backoff = new Promise(function (resolve) {
setTimeout(function () {
resolve();
}, config.retryDelay || 1);
});
// 未超过请求的时间重新发起请求
return backoff.then(function () {
return Axios(config);
});
}
);
export default Axios;
三、封装各类请求的方法
在api 下面建立 config.js 文件
代码如下
import qs from 'qs'; // 用于实现post 拼接在url后面 也就是 query类型的参数
import Axios from './api-config'; // 基础Axios的设置
import Vue from 'vue';
import axios from 'axios';
const CancelToken = axios.CancelToken; // 用于取消请求
let cancel;
// 封装常用请求接口
const config = {
/**
* get获取数据,通用方法 query类型的参数
* @param {String} url
* @param {Object} params
* @param {Object} options
*/
doGetPromise (url, params, options = {}) {
const { timeout = 30000, ...arg } = options;
// 如果参数值为空,手动赋值空字符串确保接口能收到
if (params) {
Object.keys(params).forEach(key => {
if (key === 'beginTime' || key === 'endTime') { // 有需要的就自定义
} else {
if (params[key] === null || params[key] === undefined) {
params[key] = '';
}
}
});
}
return new Promise((resolve, reject) => {
Axios.get(url, {
timeout: timeout,
...arg,
params: {
// systemId: store.state.platformInfo.systemId, // 全面接口添加systemId字段
...params
// t: new Date().getTime() // 解决IE上get请求缓存问题
},
// 取消请求
cancelToken: new CancelToken(function executor (c) {
cancel = c;
})
})
.then(response => {
resolve(response);
})
.catch(response => {
reject(response);
});
});
},
/**
* delete删除数据,通用方法
* @param {String} url
* @param {Object} params
*/
doDeletePromise (url, params) {
return new Promise((resolve, reject) => {
Axios.delete(url, {
timeout: timeout,
...arg,
params: {
...params
},
cancelToken: new CancelToken(function executor (c) {
cancel = c;
})
})
.then(response => {
resolve(response);
})
.catch(response => {
reject(response);
});
});
},
/**
* FormData数据上传,文件上传必用
* @param {String} url
* @param {FormData} formData
*/
doPostPromiseForm (url, formData) {
return new Promise((resolve, reject) => {
// 全面接口添加systemId字段
if (formData.has) {
// ie FormData没有has方法
// if (!formData.has('systemId')) {
// formData.append('systemId', store.state.platformInfo.systemId);
// }
}
Axios.post(url, formData, {
headers: {
'Content-type': 'multipart/form-data'
},
emulateJSON: false,
emulateHTTP: false,
cancelToken: new CancelToken(function executor (c) {
cancel = c;
})
})
.then(response => {
resolve(response);
})
.catch(response => {
reject(response);
});
});
},
/**
* 默认方式提交from表单数据 query类型的参数
* @param {String} url
* @param {Object} data
*/
doPostQuery (url, data) {
return new Promise((resolve, reject) => {
Axios.post(
url,
qs.stringify(data, {
arrayFormat: 'brackets'
}),
{
headers: {
'Content-type': 'application/x-www-form-urlencoded'
},
cancelToken: new CancelToken(function executor (c) {
cancel = c;
})
}
)
.then(response => {
resolve(response);
})
.catch(response => {
reject(response);
});
});
},
/**
* 默认方式提交json数据 body
* @param {String} url
* @param {Object} data
*/
doPostPromiseJson (url, data) {
return new Promise((resolve, reject) => {
// 全面接口添加systemId字段
// if (!data.hasOwnProperty('systemId')) {
// data.systemId = store.state.platformInfo.systemId;
// }
Axios.post(url, data, {
headers: {
'Content-type': 'application/json'
},
cancelToken: new CancelToken(function executor (c) {
cancel = c;
})
})
.then(res => {
resolve(res);
})
.catch(res => {
reject(res);
});
});
},
};
// 切换页面强行中断请求 router.beforeEach中用到
Vue.prototype.$cancelAjax = function (msg) {
if (cancel) {
cancel(msg || '手动中断请求');
}
};
export default config;
四、在根据页面接口配置里面引用
import config from '.@/api/config';
// get获取数据,通用方法 query类型的参数
export function queryTypical(data) {
return config.doGetPromise(
'/exchangeApi/exchange/hook/ecologicalRenovateBasicInfo/queryTypical',
data
);
}
// delete删除数据,通用方法
export function ecolRenovateConSave(data) {
return config.doDeletePromise(
'/exchangeApi/exchange/hook/ecolRenovateCon/save',
data
);
}
// post FormData数据上传,文件上传必用
export function ecolRenovateConUpdate(data) {
return config.doPostPromiseForm(
'/exchangeApi/exchange/hook/ecolRenovateCon/update',
data
);
}
// post提交from表单数据 query类型的参数
export function ecolRenovateConRemove(data) {
return config.doPostQuery(
'/exchangeApi/exchange/hook/ecolRenovateCon/remove',
data
);
}
// post提交方式提交json数据 body
export function ecolRenovateConRemove(data) {
return config.doPostPromiseJson(
'/exchangeApi/exchange/hook/ecolRenovateCon/remove',
data
);
}