1.request.js
/**
* 自定义 request 网络请求工具,基于axios
*/
import axios, { AxiosPromise, AxiosRequestConfig, AxiosResponse } from 'axios';
import { ElNotification } from 'element-plus';
import router from '@/routes';
import { getToken, setToken } from '@/utils/localToken';
// 可单独配置在 /config/settings 文件里
const settings = {
ajaxResponseNoVerifyUrl: [
'/user/login', // 用户登录
'/user/info', // 获取用户信息
],
ajaxHeadersTokenKey: 'x-token'
}
export interface ResponseData {
code: number;
data?: any;
msg?: string;
token?: string;
}
const customCodeMessage: {[key: number]: string} = {
10002: '当前用户登入信息已失效,请重新登入再操作', // 未登陆
};
const serverCodeMessage: {[key: number]: string} = {
200: '服务器成功返回请求的数据',
400: 'Bad Request',
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
500: '服务器发生错误,请检查服务器(Internal Server Error)',
502: '网关错误(Bad Gateway)',
503: '服务不可用,服务器暂时过载或维护(Service Unavailable)',
504: '网关超时(Gateway Timeout)',
};
/**
* 异常处理程序
*/
const errorHandler = (error: any) => {
const { response, message } = error;
if (message === 'CustomError') {
// 自定义错误
const { config, data } = response;
const { url, baseURL} = config;
const { code, msg } = data;
const reqUrl = url.split("?")[0].replace(baseURL, '');
const noVerifyBool = settings.ajaxResponseNoVerifyUrl.includes(reqUrl);
if (!noVerifyBool) {
ElNotification({
type: 'error',
title: `提示`,
message: customCodeMessage[code] || msg || 'Error',
});
if (code === 10002) {
router.replace('/user/login');
}
}
} else if (message === 'CancelToken') {
// 取消请求 Token
// eslint-disable-next-line no-console
} else if (response && response.status) {
const errorText = serverCodeMessage[response.status] || response.statusText;
const { status, request } = response;
ElNotification({
type: 'error',
title: `请求错误 ${status}: ${request.responseURL}`,
message: errorText,
});
} else if (!response) {
ElNotification({
type: 'error',
title: '网络异常',
message: '您的网络发生异常,无法连接服务器',
});
}
return Promise.reject(error);
}
/**
* 配置request请求时的默认参数
*/
const request = axios.create({
baseURL: process.env.VUE_APP_APIHOST, // url = api url + request url
withCredentials: true, // 当跨域请求时发送cookie
timeout: 0 // 请求超时时间,5000(单位毫秒) / 0 不做限制
});
/**
* 请求前
* 请求拦截器
*/
request.interceptors.request.use(
async (config: AxiosRequestConfig & { cType?: boolean }) => {
// 如果设置了cType 说明是自定义 添加 Content-Type类型 为自定义post 做铺垫
if (config['cType']) {
config.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
}
// 自定义添加token header
const headerToken = await getToken();
if (headerToken) {
config.headers[settings.ajaxHeadersTokenKey] = headerToken;
}
return config;
}
);
/**
* 请求后
* 响应拦截器
*/
request.interceptors.response.use(
async (response: AxiosResponse) => {
const res: ResponseData = response.data;
const { code, token } = res;
// 自定义状态码验证
if (code !== 0) {
return Promise.reject({
response,
message: 'CustomError',
});
}
// 重置刷新token
if (token) {
await setToken(token);
}
return response;
}
);
export default function(config: AxiosRequestConfig): AxiosPromise<any> {
return request(config).then((response: AxiosResponse) => response.data).catch(error => errorHandler(error));
}
2.localToken.js
/**
* 自定义 token 操作
*/
import localforage from 'localforage';
// 可单独配置在 /config/settings 文件里
const settinpgs = {
siteTokenKey: 'admin_element_vue_token'
}
/**
* 获取本地Token
*/
export const getToken = async (): Promise<string | null> => {
return await localforage.getItem(settings.siteTokenKey);
};
/**
* 设置存储本地Token
*/
export const setToken = async (token: string): Promise<boolean> => {
try {
await localforage.setItem(settings.siteTokenKey, token);
return true;
} catch (error) {
return false;
}
};
/**
* 移除本地Token
*/
export const removeToken = async (): Promise<boolean> => {
try {
await localforage.removeItem(settings.siteTokenKey);
return true;
} catch (error) {
return false;
}
};