import axios, { AxiosPromise, Method } from 'axios'
|
import type { AxiosRequestConfig } from 'axios'
|
import { ElLoading, LoadingOptions, ElNotification } from 'element-plus'
|
import router from '@/router/index'
|
import { close, start } from '@/utils/nprogress' // 页面加载进度条
|
import { useUserInfo } from '@/stores/modules/userInfo'
|
const default_login_URL = import.meta.env.VITE_BASE_LOGIN_URL as string;
|
|
const userInfoStore = useUserInfo()
|
|
const pendingMap = new Map() //当前所有请求的唯一key值集合
|
const loadingInstance: LoadingInstance = {
|
target: null,
|
count: 0,
|
}
|
|
export const getUrl = (): string => {
|
const value: string = import.meta.env.VITE_BASE_PATH as string
|
return value
|
}
|
export const getUrlPort = (): string => {
|
let url = getUrl()
|
return new URL(url).port
|
}
|
|
const noTokenUrlList: [string | undefined] = ['/authentication/admin/login'] // 不需要传递token的接口请求路径集合
|
|
/*
|
* 创建Axios
|
* 默认开启`reductDataFormat(简洁响应)`,返回类型为`ApiPromise`
|
* 关闭`reductDataFormat`,返回类型则为`AxiosPromise`
|
*/
|
function createAxios(
|
axiosConfig: AxiosRequestConfig,
|
options: Options = {},
|
loading: LoadingOptions = {}
|
): ApiPromise | AxiosPromise {
|
const Axios = axios.create({
|
baseURL: getUrl(),
|
timeout: 1000 * 300,
|
headers: {
|
'Content-Type': 'application/json;charset=UTF-8',
|
},
|
method: 'post',
|
})
|
options = Object.assign(
|
{
|
CancelDuplicateRequest: false, //是否开启取消重复请求,默认true
|
loading: false, //是否开启页面级loading层效果,默认false
|
reductDataFormat: true, //是否开启简洁的数据结构响应,默认true
|
showErrorMessage: true, //是否开启接口错误信息提示,默认true
|
showCodeMessage: true, //是否开启code不为0时的信息提示,默认true
|
showSuccessMessage: false, // 是否开启code为0时的信息提示, 默认为false
|
},
|
options
|
)
|
/* 请求拦截 */
|
Axios.interceptors.request.use(
|
(config) => {
|
removePending(config)
|
options.CancelDuplicateRequest && addPending(config)
|
// 创建loading实例
|
if (options.loading) {
|
loadingInstance.count++
|
if (loadingInstance.count === 1) {
|
loadingInstance.target = ElLoading.service(loading)
|
}
|
}
|
// 进度条加载
|
start()
|
//自动携带token
|
if (config.headers) {
|
if (!noTokenUrlList.includes(config.url)) {
|
// 从状态管理器获取token数据
|
config.headers['token'] = userInfoStore.getAdminToken
|
if (localStorage.getItem('lastRecordTime')) {
|
config.headers["lastRecordTime"] = localStorage.getItem('lastRecordTime') as string;
|
}
|
config.headers["nowTime"] = new Date().getTime();
|
console.log('nowTime',config.headers["nowTime"])
|
}
|
}
|
return config
|
},
|
(error) => {
|
return Promise.reject(error)
|
}
|
)
|
/* 响应拦截 */
|
Axios.interceptors.response.use(
|
(response) => {
|
removePending(response.config)
|
options.loading && closeLoading(options) // 关闭loading
|
// 关闭进度条
|
close()
|
const { config } = response
|
// 下载文件 数据流格式特殊处理
|
if (config.url?.includes('common/filePreview')) {
|
return response
|
}
|
const isFile = response.headers['content-type'] === 'application/octet-stream'
|
if(isFile) {
|
return response
|
}
|
if (response.data && response.data.code == 200) {
|
return response.data
|
} else {
|
if (response.data.code == 401) {
|
userInfoStore.removeToken()
|
// 跳到扫码登录
|
// window.location.href=default_login_URL
|
router.replace({
|
path: '/login',
|
})
|
// window.location.href = 'http://36.139.126.109:7089/loginDem'
|
} else {
|
ElNotification({
|
type: 'error',
|
message:
|
response.data.msg ||
|
response.data.message ||
|
response.data.errmsg,
|
})
|
}
|
return response.data
|
}
|
},
|
(error) => {
|
error.config && removePending(error.config)
|
options.loading && closeLoading(options) // 关闭loading
|
// 关闭进度条
|
close()
|
options.showErrorMessage && httpErrorStatusHandle(error) // 处理错误状态码
|
return Promise.reject(error) // 错误继续返回给到具体页面
|
}
|
)
|
return Axios(axiosConfig)
|
}
|
|
export default createAxios
|
|
/**
|
* 处理异常
|
* @param {*} error
|
*/
|
function httpErrorStatusHandle(error: any) {
|
if (axios.isCancel(error)) return console.error(error.message)
|
let message = ''
|
if (error && error.response) {
|
switch (error.response.status) {
|
case 302:
|
message = '接口重定向了!'
|
break
|
case 400:
|
message = '参数不正确!'
|
break
|
case 401:
|
message = '您未登录,或者登录已经超时,请先登录!'
|
break
|
case 403:
|
message = '您没有权限操作!'
|
break
|
case 404:
|
message = `请求地址出错: ${error.response.config.url}`
|
break // 在正确域名下
|
case 408:
|
message = '请求超时!'
|
break
|
case 409:
|
message = '系统已存在相同数据!'
|
break
|
case 500:
|
message = '服务器内部错误!'
|
break
|
case 501:
|
message = '服务未实现!'
|
break
|
case 502:
|
message = '网关错误!'
|
break
|
case 503:
|
message = '服务不可用!'
|
break
|
case 504:
|
message = '服务暂时无法访问,请稍后再试!'
|
break
|
case 505:
|
message = 'HTTP版本不受支持!'
|
break
|
default:
|
message = '异常问题,请联系管理员!'
|
break
|
}
|
}
|
if (error.message.includes('timeout')) message = '网络请求超时!'
|
if (error.message.includes('Network'))
|
message = window.navigator.onLine ? '服务端异常!' : '您断网了!'
|
|
ElNotification({
|
type: 'error',
|
message,
|
})
|
}
|
|
// export function requestPayload(method: Method, data: anyObj) {
|
// if (method.toUpperCase() == 'GET') {
|
// return {
|
// params: data
|
// }
|
// } else if (method.toUpperCase() == 'POST') {
|
// return {
|
// data: data
|
// }
|
// }
|
// }
|
/**
|
* 关闭Loading层实例
|
*/
|
function closeLoading(options: Options) {
|
if (options.loading && loadingInstance.count > 0) loadingInstance.count--
|
if (loadingInstance.count === 0) {
|
loadingInstance.target.close()
|
loadingInstance.target = null
|
}
|
}
|
|
/**
|
* 储存每个请求的唯一cancel回调, 以此为标识
|
*/
|
function addPending(config: AxiosRequestConfig) {
|
const pendingKey = getPendingKey(config)
|
config.cancelToken =
|
config.cancelToken ||
|
new axios.CancelToken((cancel) => {
|
if (!pendingMap.has(pendingKey)) {
|
pendingMap.set(pendingKey, cancel)
|
}
|
})
|
}
|
|
/**
|
* 删除重复的请求
|
*/
|
function removePending(config: AxiosRequestConfig) {
|
const pendingKey = getPendingKey(config)
|
// console.log('pendingMap', pendingMap)
|
if (pendingMap.has(pendingKey)) {
|
const cancelToken = pendingMap.get(pendingKey)
|
cancelToken(pendingKey)
|
pendingMap.delete(pendingKey)
|
}
|
}
|
|
/**
|
* 生成每个请求的唯一key
|
*/
|
function getPendingKey(config: AxiosRequestConfig) {
|
let { url, method, data, headers } = config
|
// if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
|
return [
|
url,
|
method,
|
//后面根据业务再加
|
// headers && headers.batoken ? headers.batoken : '',
|
// headers && headers['ba-user-token'] ? headers['ba-user-token'] : '',
|
// JSON.stringify(params),
|
JSON.stringify(data),
|
].join('&')
|
}
|
|
interface LoadingInstance {
|
target: any
|
count: number
|
}
|
|
interface Options {
|
// 是否开启取消重复请求, 默认为 true
|
CancelDuplicateRequest?: boolean
|
// 是否开启loading层效果, 默认为false
|
loading?: boolean
|
// 是否开启简洁的数据结构响应, 默认为true
|
reductDataFormat?: boolean
|
// 是否开启接口错误信息展示,默认为true
|
showErrorMessage?: boolean
|
// 是否开启code不为0时的信息提示, 默认为true
|
showCodeMessage?: boolean
|
// 是否开启code为0时的信息提示, 默认为false
|
showSuccessMessage?: boolean
|
}
|
|
// 1、接口请求返回值 code 值 定义
|
// 2、get请求 post请求 Content-type 分别是什么
|
// 3、错误返回message,前端弹出
|