提交 | 用户 | age
|
2f6253
|
1 |
// axios配置 可自行根据项目进行更改,只需更改该文件即可,其他文件可以不动 |
陈 |
2 |
// The axios configuration can be changed according to the project, just change the file, other files can be left unchanged |
|
3 |
|
|
4 |
import type { AxiosResponse } from 'axios'; |
|
5 |
import type { CreateAxiosOptions, RequestOptions, Result } from './types'; |
|
6 |
import { VAxios } from './Axios'; |
|
7 |
import { AxiosTransform } from './axiosTransform'; |
|
8 |
|
|
9 |
import { checkStatus } from './checkStatus'; |
|
10 |
|
ba068b
|
11 |
import { useGlobSetting } from '/@/hooks/setting'; |
2f6253
|
12 |
import { useMessage } from '/@/hooks/web/useMessage'; |
陈 |
13 |
|
|
14 |
import { RequestEnum, ResultEnum, ContentTypeEnum } from '/@/enums/httpEnum'; |
|
15 |
|
|
16 |
import { isString } from '/@/utils/is'; |
|
17 |
import { setObjToUrlParams, deepMerge } from '/@/utils'; |
710158
|
18 |
import { errorStore } from '/@/store/modules/error'; |
e83cb0
|
19 |
import { errorResult } from './const'; |
190112
|
20 |
import { useI18n } from '/@/hooks/web/useI18n'; |
f646e3
|
21 |
import { createNow, formatRequestDate } from './helper'; |
be3a3e
|
22 |
import { userStore } from '/@/store/modules/user'; |
2f6253
|
23 |
|
737b1b
|
24 |
const globSetting = useGlobSetting(); |
2f6253
|
25 |
const prefix = globSetting.urlPrefix; |
陈 |
26 |
const { createMessage, createErrorModal } = useMessage(); |
|
27 |
|
|
28 |
/** |
|
29 |
* @description: 数据处理,方便区分多种处理方式 |
|
30 |
*/ |
|
31 |
const transform: AxiosTransform = { |
|
32 |
/** |
|
33 |
* @description: 处理请求数据 |
|
34 |
*/ |
|
35 |
transformRequestData: (res: AxiosResponse<Result>, options: RequestOptions) => { |
962f90
|
36 |
const { t } = useI18n(); |
2f6253
|
37 |
const { isTransformRequestResult } = options; |
陈 |
38 |
// 不进行任何处理,直接返回 |
|
39 |
// 用于页面代码可能需要直接获取code,data,message这些信息时开启 |
|
40 |
if (!isTransformRequestResult) { |
|
41 |
return res.data; |
|
42 |
} |
|
43 |
// 错误的时候返回 |
|
44 |
|
|
45 |
const { data } = res; |
|
46 |
if (!data) { |
|
47 |
// return '[HTTP] Request has no return value'; |
|
48 |
return errorResult; |
|
49 |
} |
|
50 |
// 这里 code,result,message为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式 |
|
51 |
const { code, result, message } = data; |
|
52 |
|
|
53 |
// 这里逻辑可以根据项目进行修改 |
|
54 |
const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS; |
|
55 |
if (!hasSuccess) { |
|
56 |
if (message) { |
|
57 |
// errorMessageMode=‘modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误 |
|
58 |
if (options.errorMessageMode === 'modal') { |
962f90
|
59 |
createErrorModal({ title: t('sys.api.errorTip'), content: message }); |
4ce1d5
|
60 |
} else if (options.errorMessageMode === 'message') { |
2f6253
|
61 |
createMessage.error(message); |
陈 |
62 |
} |
|
63 |
} |
|
64 |
Promise.reject(new Error(message)); |
|
65 |
return errorResult; |
|
66 |
} |
|
67 |
|
|
68 |
// 接口请求成功,直接返回结果 |
|
69 |
if (code === ResultEnum.SUCCESS) { |
e83cb0
|
70 |
return result; |
2f6253
|
71 |
} |
陈 |
72 |
// 接口请求错误,统一提示错误信息 |
|
73 |
if (code === ResultEnum.ERROR) { |
|
74 |
if (message) { |
|
75 |
createMessage.error(data.message); |
|
76 |
Promise.reject(new Error(message)); |
|
77 |
} else { |
962f90
|
78 |
const msg = t('sys.api.errorMessage'); |
2f6253
|
79 |
createMessage.error(msg); |
陈 |
80 |
Promise.reject(new Error(msg)); |
|
81 |
} |
|
82 |
return errorResult; |
|
83 |
} |
|
84 |
// 登录超时 |
|
85 |
if (code === ResultEnum.TIMEOUT) { |
962f90
|
86 |
const timeoutMsg = t('sys.api.timeoutMessage'); |
2f6253
|
87 |
createErrorModal({ |
962f90
|
88 |
title: t('sys.api.operationFailed'), |
2f6253
|
89 |
content: timeoutMsg, |
陈 |
90 |
}); |
|
91 |
Promise.reject(new Error(timeoutMsg)); |
|
92 |
return errorResult; |
|
93 |
} |
|
94 |
return errorResult; |
|
95 |
}, |
|
96 |
|
|
97 |
// 请求之前处理config |
|
98 |
beforeRequestHook: (config, options) => { |
f646e3
|
99 |
const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true } = options; |
2f6253
|
100 |
|
陈 |
101 |
if (joinPrefix) { |
|
102 |
config.url = `${prefix}${config.url}`; |
|
103 |
} |
|
104 |
|
|
105 |
if (apiUrl && isString(apiUrl)) { |
|
106 |
config.url = `${apiUrl}${config.url}`; |
|
107 |
} |
ac1a36
|
108 |
const params = config.params || {}; |
6b3195
|
109 |
if (config.method?.toUpperCase() === RequestEnum.GET) { |
ac1a36
|
110 |
if (!isString(params)) { |
c96002
|
111 |
// 给 get 请求加上时间戳参数,避免从缓存中拿数据。 |
V |
112 |
config.params = Object.assign(params || {}, createNow(joinTime, false)); |
2f6253
|
113 |
} else { |
陈 |
114 |
// 兼容restful风格 |
ac1a36
|
115 |
config.url = config.url + params + `${createNow(joinTime, true)}`; |
34c09f
|
116 |
config.params = undefined; |
2f6253
|
117 |
} |
陈 |
118 |
} else { |
ac1a36
|
119 |
if (!isString(params)) { |
V |
120 |
formatDate && formatRequestDate(params); |
|
121 |
config.data = params; |
34c09f
|
122 |
config.params = undefined; |
2f6253
|
123 |
if (joinParamsToUrl) { |
陈 |
124 |
config.url = setObjToUrlParams(config.url as string, config.data); |
|
125 |
} |
|
126 |
} else { |
|
127 |
// 兼容restful风格 |
ac1a36
|
128 |
config.url = config.url + params; |
34c09f
|
129 |
config.params = undefined; |
2f6253
|
130 |
} |
陈 |
131 |
} |
|
132 |
return config; |
|
133 |
}, |
|
134 |
|
|
135 |
/** |
|
136 |
* @description: 请求拦截器处理 |
|
137 |
*/ |
|
138 |
requestInterceptors: (config) => { |
|
139 |
// 请求之前处理config |
be3a3e
|
140 |
const token = userStore.getTokenState; |
2f6253
|
141 |
if (token) { |
陈 |
142 |
// jwt token |
|
143 |
config.headers.Authorization = token; |
|
144 |
} |
|
145 |
return config; |
|
146 |
}, |
|
147 |
|
|
148 |
/** |
|
149 |
* @description: 响应错误处理 |
|
150 |
*/ |
|
151 |
responseInterceptorsCatch: (error: any) => { |
962f90
|
152 |
const { t } = useI18n(); |
710158
|
153 |
errorStore.setupErrorHandle(error); |
2f6253
|
154 |
const { response, code, message } = error || {}; |
de5bf7
|
155 |
const msg: string = response?.data?.error?.message ?? ''; |
V |
156 |
const err: string = error?.toString?.() ?? ''; |
2f6253
|
157 |
try { |
陈 |
158 |
if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) { |
962f90
|
159 |
createMessage.error(t('sys.api.apiTimeoutMessage')); |
2f6253
|
160 |
} |
6b3195
|
161 |
if (err?.includes('Network Error')) { |
2f6253
|
162 |
createErrorModal({ |
962f90
|
163 |
title: t('sys.api.networkException'), |
V |
164 |
content: t('sys.api.networkExceptionMsg'), |
2f6253
|
165 |
}); |
陈 |
166 |
} |
|
167 |
} catch (error) { |
|
168 |
throw new Error(error); |
|
169 |
} |
6b3195
|
170 |
checkStatus(error?.response?.status, msg); |
661db0
|
171 |
return Promise.reject(error); |
2f6253
|
172 |
}, |
陈 |
173 |
}; |
|
174 |
|
|
175 |
function createAxios(opt?: Partial<CreateAxiosOptions>) { |
|
176 |
return new VAxios( |
|
177 |
deepMerge( |
|
178 |
{ |
|
179 |
timeout: 10 * 1000, |
|
180 |
// 基础接口地址 |
|
181 |
// baseURL: globSetting.apiUrl, |
|
182 |
// 接口可能会有通用的地址部分,可以统一抽取出来 |
|
183 |
prefixUrl: prefix, |
|
184 |
headers: { 'Content-Type': ContentTypeEnum.JSON }, |
f646e3
|
185 |
// 如果是form-data格式 |
V |
186 |
// headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED }, |
2f6253
|
187 |
// 数据处理方式 |
陈 |
188 |
transform, |
|
189 |
// 配置项,下面的选项都可以在独立的接口请求中覆盖 |
|
190 |
requestOptions: { |
|
191 |
// 默认将prefix 添加到url |
|
192 |
joinPrefix: true, |
|
193 |
// 需要对返回数据进行处理 |
|
194 |
isTransformRequestResult: true, |
|
195 |
// post请求的时候添加参数到url |
|
196 |
joinParamsToUrl: false, |
|
197 |
// 格式化提交参数时间 |
|
198 |
formatDate: true, |
|
199 |
// 消息提示类型 |
4ce1d5
|
200 |
errorMessageMode: 'message', |
2f6253
|
201 |
// 接口地址 |
陈 |
202 |
apiUrl: globSetting.apiUrl, |
f646e3
|
203 |
// 是否加入时间戳 |
V |
204 |
joinTime: true, |
2f6253
|
205 |
}, |
陈 |
206 |
}, |
|
207 |
opt || {} |
|
208 |
) |
|
209 |
); |
|
210 |
} |
|
211 |
export const defHttp = createAxios(); |
|
212 |
|
|
213 |
// other api url |
|
214 |
// export const otherHttp = createAxios({ |
|
215 |
// requestOptions: { |
|
216 |
// apiUrl: 'xxx', |
|
217 |
// }, |
|
218 |
// }); |