前言:
当项目中用到了非常多的接口时,我们不可能每次都引入axios,然后使用axios来发送请求;这样用起来不仅代码赘余且不利于后期的维护,
因此我们需要封装axios,把所有的接口统一放在一个模块内(我一般命名为api或者model),在需要调用接口的时候引用这个模块内封装好的接口函数即可。
一般的请求流程大致分为三个步骤(一般方式)
1.请求进入请求拦截器之前
请求调整或者配置用户标识:
instance.interceptors.request.use((reqConfig) => {
const token = pmsStore.state.token;
if (token) {
reqConfig.headers['Authorization'] = 'Bearer ' + token;
}
return reqConfig;
}, (error) => Promise.reject(error));
2.真正的请求(创建axios实例)
const instance = axios.create({
baseURL: network.baseDomain + network.basePath,
timeout: network.timeout,
withCredentials: false,
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
});
3.请求从响应拦截器出来后
对相应的错误进行处理
-
网络错误处理(断网)
-
授权错误处理(没有权限 401)
-
超时处理(403)
-
普通错误处理等等
instance.interceptors.response.use((response) => { // 请求成功 if (response.data.success && response.status <= 200) { return { data: response.data.result, errorMessage: null, success: true }; } message.error(response?.data?.error?.message ?? "请求出错"); return Promise.reject({ data: null, success: false, errorMessage: response.data.error.message }); }, (error) => { const responseData = error.response.data; const res = { success: false, data: null, errorMessage: 'Request error' }; if (error.response) { switch (error.response.status) { case 403: // Todo: 处理 token 过期 break; case 500: const isStr = typeof responseData === 'string'; res.errorMessage = isStr ? responseData : responseData.error.message; break; } message.error(res.errorMessage); return Promise.reject(res); } // 断网 if (!window.navigator.onLine) { res.errorMessage = '网络已断开'; } message.error(res.errorMessage ?? '请求出错'); return Promise.reject(res); });
针对接口所有的请求类型进行处理 (get post pull等等)
class Http {
/**
* @param {AxiosRequestConfig} config
* @return {Promise<HttpResponse>}
*/
static request(config) {
return instance(config);
}
/**
* GET
*
* @param {string} url
* @param {object} query
* @return {Promise<HttpResponse | HttpResponsePager>}
*/
static get({ url, query = null }) {
return instance.get(url, {
params: query
});
}
/**
* POST
*
* @param {string} url
* @param {object} data
* @param {object} query
* @return {Promise<HttpResponse>}
*/
static post({ url, data = null, query = null }) {
return instance.post(url, data, {
params: query
});
}
/**
* PUT
*
* @param {string} url
* @param {object} data
* @param {object} query
* @return {Promise<HttpResponse>}
*/
static put({ url, data = null, query = null }) {
return instance.put(url, data, {
params: query
});
}
}
export default Http;
在统一封装接口的模块(一般是api或者model)引入封装的axios
import Http from "@/utils/Http";
export default {
//查询
getInfo(params) {
return Http.get({
url: '请求路径',
query: {
...params
},
});
},
}
接口使用
import Api from "@/api/InfoManage/index";
search() {
const data = {
page: this.pagination.page,
rows: this.pagination.pageSize,
}
Api.getInfo({...data})
.then((res) => {
this.tableData = res.data.items;
this.pagination.total = res.data.totalCount;
})
.catch((err) => {
console.log(err);
})
},
其他方式:直接封装一个axios请求
import axios from "axios";
import {message} from 'ant-design-vue'
import {requestRouter} from '@/router'
import {removeToken, updateToken} from './token'
import config from './config';
//配置基准路径和默认超时时间
const hostName = config.baseURL;
axios.defaults.baseURL = hostName;
axios.defaults.timeout = config.timeout;
//封装axios请求
const BizRequest = (
url,
method = "get",
data = {},
params = {},
grant_type //该字段存在表示用户已登录,token存在(业务需求)
) => {
let options = {
url,
method,
data,
params,
headers: {},
};
if (grant_type) {
options = {
...options,
headers: {
"Content-Type": "application/json"
},
data: {...data}
};
}
return new Promise((resolve, reject) => {
//配置用户标识
const tokenString = window.localStorage.getItem("ems_access_token");
if (tokenString) {
axios.defaults.headers["Authorization"] = "Bearer " + tokenString;
}
axios(options)
.then(async (response) => {
if (response.status === 200) {
//更新用户状态
if (grant_type) {
updateToken(
response.data.result.accessToken,
response.data.result.encryptedAccessToken,
response.data.result.expireInSeconds
);
resolve(response);
} else {
if (!response.data.success) {
message.error(response?.data?.error?.details || response?.data?.error?.message);
reject(response.data)
} else {
resolve(response.data);
}
}
}
})
.catch(async (err) => {
//对错误进行处理
if (err?.response?.status === 401) {
message.error("登陆凭证过期,请重新登陆!");
removeToken();
requestRouter.replace('/login');
} else {
message.error(err?.response?.data?.error?.details || err?.response?.data?.error?.message);
}
reject(err?.response);
});
});
};
export default request;
export {removeToken};
在统一封装接口的模块引入封装的axios
import request from '@/utils/request'
export default {
query(params) {
return request('请求地址', "post", null, params);
},
create(data) {
return request('请求地址', 'post', data);
},
update(data) {
return request('请求地址', 'post', data);
},
delete(params) {
return request('请求地址', 'get', null, params);
}
};
接口使用
import Api from "@/api/bigEvent";
onDelete(id) {
Api.delete({ id }).then(() => {
this.$message.success("删除成功");
this.search();
});
},