| | |
| | | import axios, {AxiosError, AxiosResponse} from 'axios' |
| | | import {useRouter} from 'vue-router' |
| | | import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios' |
| | | import Qs from 'qs' |
| | | import { useBedsideAuxiliaryScreenStore } from '@/store/bedsideAuxiliaryScreen' |
| | | import { ElMessage } from 'element-plus/es' |
| | | |
| | | const BASE_URL = import.meta.env.VITE_BASIC_API |
| | | // ====== 配置 ====== |
| | | const BASE_URL = import.meta.env.VITE_API_BASE_URL |
| | | const TIME_OUT = 60 * 1 * 1000 |
| | | |
| | | const TIME_OUT = 60 * 2 * 1000 |
| | | // 正在进行中的请求列表 |
| | | let reqList: any[] = [] // 如果某个api存在这个数组里,说明该api暂时无法再次请求 |
| | | // 正在进行中的请求列表,避免重复请求 |
| | | let reqList: string[] = [] |
| | | |
| | | /** |
| | | * 允许某个请求可以继续进行 |
| | | * @param {array} reqList 全部请求列表 |
| | | * @param {string} url 请求地址 |
| | | */ |
| | | const allowRequest = function (reqList: any[], url: any) { |
| | | for (let i = 0; i < reqList.length; i++) { |
| | | if (reqList[i] === url) { |
| | | reqList.splice(i, 1) |
| | | break |
| | | } |
| | | } |
| | | } |
| | | /** |
| | | * 创建axios实例 |
| | | * 允许某个请求再次发送 |
| | | */ |
| | | const instance = axios.create({ |
| | | baseURL: BASE_URL, |
| | | timeout: TIME_OUT, |
| | | paramsSerializer: function(params) {//序列化请求参数,避免get请求参数出现&,空格等识别错误的问题 |
| | | return Qs.stringify(params, {arrayFormat: 'brackets'}) |
| | | }, |
| | | }) |
| | | |
| | | const errorHandle = (status: number, error:any): void => { |
| | | // HTTP状态码判断 |
| | | switch (status) { |
| | | case 401: |
| | | return alert(`Error Code: ${status}, Message: ${error.msg || '登录失效,请重新登录'}`) |
| | | case 403: |
| | | return alert(`Error Code: ${status}, Message: ${error.msg || '你没有访问权限'}`) |
| | | case 500: |
| | | return alert(`Error Code: ${status}, Message: ${error.msg || '后台错误,请联系管理员'}`) |
| | | case 502: |
| | | return alert(`Error Code: ${status}, Message: ${error.msg || '平台环境异常'}`) |
| | | default: |
| | | alert(`Error Code: ${status}, Message: ${error.msg || '未知错误,请刷新重试'}`) |
| | | } |
| | | const allowRequest = (url?: string) => { |
| | | if (!url) return |
| | | const idx = reqList.indexOf(url) |
| | | if (idx > -1) reqList.splice(idx, 1) |
| | | } |
| | | |
| | | // 前置拦截器(发起请求之前的拦截) |
| | | /** |
| | | * 创建 axios 实例 |
| | | */ |
| | | const instance = axios.create({ |
| | | baseURL: BASE_URL, |
| | | timeout: TIME_OUT, |
| | | paramsSerializer: (params) => Qs.stringify(params, { arrayFormat: 'brackets' }), |
| | | }) |
| | | |
| | | // ====== 错误处理函数 ====== |
| | | const errorHandle = (status: number, error: any): void => { |
| | | const msg = error?.msg || error?.message || '' |
| | | switch (status) { |
| | | case 401: |
| | | ElMessage.error(`Error Code: 401, Message: ${msg || '登录失效,请重新登录'}`); |
| | | break |
| | | case 403: |
| | | ElMessage.error(`Error Code: 403, Message: ${msg || '你没有访问权限'}`); |
| | | break |
| | | case 500: |
| | | ElMessage.error(`Error Code: 500, Message: ${msg || '后台错误,请联系管理员'}`); |
| | | break |
| | | case 502: |
| | | alert() |
| | | ElMessage.error(`Error Code: 502, Message: ${msg || '平台环境异常'}`); |
| | | break |
| | | default: |
| | | ElMessage.error(`Error Code: ${status}, Message: ${msg || '未知错误,请刷新重试'}`); |
| | | } |
| | | } |
| | | |
| | | // ====== 请求拦截 ====== |
| | | instance.interceptors.request.use( |
| | | (response:any) =>{ |
| | | if (useBedsideAuxiliaryScreenStore().userInfo?.token) { |
| | | response.headers.common['Authorization'] = 'Bearer '+ `${useBedsideAuxiliaryScreenStore().userInfo?.token}` |
| | | } |
| | | let cancel |
| | | // 设置cancelToken对象 |
| | | response.cancelToken = new axios.CancelToken(function(c) { |
| | | cancel = c |
| | | }) |
| | | return response |
| | | }, |
| | | (error) => Promise.reject(error) |
| | | (config: InternalAxiosRequestConfig) => { |
| | | const store = useBedsideAuxiliaryScreenStore() |
| | | |
| | | // 加 token |
| | | if (store.userInfo?.token) { |
| | | config.headers.set('Authorization', `Bearer ${store.userInfo.token}`) |
| | | } |
| | | |
| | | // 防止同一接口短时间内重复请求 |
| | | if (config.url) { |
| | | if (reqList.includes(config.url)) { |
| | | return Promise.reject(new axios.Cancel(`重复请求:${config.url}`)) |
| | | } else { |
| | | reqList.push(config.url) |
| | | } |
| | | } |
| | | |
| | | return config |
| | | }, |
| | | (error) => Promise.reject(error), |
| | | ) |
| | | |
| | | // 后置拦截器(获取到响应时的拦截) |
| | | // ====== 响应拦截 ====== |
| | | instance.interceptors.response.use( |
| | | (res: AxiosResponse) => { |
| | | |
| | | (res: AxiosResponse) => { |
| | | // 增加延迟,相同请求不得在短时间内重复发送 |
| | | setTimeout(() => { |
| | | allowRequest(reqList, res.config.url) |
| | | }, 1000) // 上一次请求返回后过1s才允许再次请求 |
| | | if (String(res.status).indexOf('2') !== 0) { |
| | | return { |
| | | code: res.status, |
| | | message: res.data.message || '请求异常,请刷新重试', |
| | | result: false |
| | | } |
| | | } |
| | | if (res.data.code===200){ |
| | | return res.data |
| | | } |
| | | // 返回异常 |
| | | else { |
| | | // Toast(res.data.message) |
| | | // 白名单,直接返回不提示 |
| | | const whiteList: string[] = ["/patient/hemo/med/record/updateSchemeTool","/patient/hemo/med/monitor/data/prepareAdd"]; |
| | | const requestUrl = res.request.responseURL; |
| | | const isInWhiteList = whiteList.some(item => requestUrl.includes(item)); |
| | | if(isInWhiteList) return Promise.reject(res.data); |
| | | |
| | | return Promise.reject(res.data) |
| | | } |
| | | // return Promise.reject(instance.interceptors.response) |
| | | }, |
| | | (error: AxiosError) => { |
| | | if (axios.isCancel(error)) { |
| | | console.log(error.message); |
| | | } |
| | | else { |
| | | setTimeout(() => { |
| | | allowRequest(reqList, error.config.url) |
| | | }, 1000) // 请求失败返回后过1s才允许再次请求 |
| | | } |
| | | if (error && error.response) { |
| | | // 请求已发出,但是不在2xx的范围 |
| | | errorHandle(error.response.status, error.response) |
| | | if (error.response.status===401){ |
| | | Dialog.confirm({ |
| | | title: '提示', |
| | | message: |
| | | '是否需要退出登录?', |
| | | }) |
| | | .then(() => { |
| | | Session.clear(); // 清除浏览器全部临时缓存 |
| | | window.location.href = '/'; // 去登录页 |
| | | }) |
| | | .catch(() => { |
| | | Toast('取消操作') |
| | | }) |
| | | } |
| | | return Promise.reject(error.response) |
| | | } |
| | | Toast('网络请求失败, 请刷新重试') |
| | | return Promise.reject(error) |
| | | setTimeout(() => allowRequest(res.config.url), 1000) |
| | | if (String(res.status).charAt(0) !== '2') { |
| | | return Promise.reject({ |
| | | code: res.status, |
| | | message: res.data?.message || '请求异常,请刷新重试', |
| | | }) |
| | | } |
| | | if (res.data?.code === 200) return res.data |
| | | const whiteList: string[] = [] |
| | | const requestUrl: string = res?.config?.url || '' |
| | | const isInWhiteList = whiteList.some((item) => requestUrl.includes(item)) |
| | | ElMessage.error(res.data.message); |
| | | if (isInWhiteList) return Promise.reject(res.data) |
| | | return Promise.reject(res.data) |
| | | }, |
| | | |
| | | |
| | | (err: unknown) => { |
| | | |
| | | const anyErr = err as any |
| | | const configUrl = anyErr?.config?.url |
| | | // 失败后 1s 允许再次请求 |
| | | setTimeout(() => allowRequest(configUrl), 1000) |
| | | |
| | | // 先判断是否是取消请求 |
| | | if (axios.isCancel(err as any)) { |
| | | console.warn('请求被取消:', (err as any)?.message) |
| | | return Promise.reject(err) |
| | | } |
| | | |
| | | // 判断是否为 axios 的错误类型(有 response) |
| | | if (axios.isAxiosError(err)) { |
| | | const axErr = err // 现在 TypeScript 知道这是 AxiosError |
| | | if (axErr.response) { |
| | | // 使用你现有的错误处理函数 |
| | | errorHandle(axErr.response.status, axErr.response.data) |
| | | |
| | | if (axErr.response.status === 401) { |
| | | ElMessage.error('请登录'); |
| | | } |
| | | return Promise.reject(axErr.response.data || axErr.response) |
| | | } |
| | | |
| | | ElMessage.error('网络请求失败, 请刷新重试'); |
| | | return Promise.reject(axErr) |
| | | } |
| | | |
| | | //(未知错误) |
| | | ElMessage.error('网络请求失败, 请刷新重试'); |
| | | return Promise.reject(err) |
| | | }, |
| | | ) |
| | | |
| | | export default instance |