提交 | 用户 | 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'; |
b6d5b0
|
5 |
import type { RequestOptions, Result } from '/#/axios'; |
b7ce74
|
6 |
import type { AxiosTransform, CreateAxiosOptions } from './axiosTransform'; |
V |
7 |
import { VAxios } from './Axios'; |
2f6253
|
8 |
import { checkStatus } from './checkStatus'; |
ba068b
|
9 |
import { useGlobSetting } from '/@/hooks/setting'; |
2f6253
|
10 |
import { useMessage } from '/@/hooks/web/useMessage'; |
陈 |
11 |
import { RequestEnum, ResultEnum, ContentTypeEnum } from '/@/enums/httpEnum'; |
|
12 |
import { isString } from '/@/utils/is'; |
b7ce74
|
13 |
import { getToken } from '/@/utils/auth'; |
2f6253
|
14 |
import { setObjToUrlParams, deepMerge } from '/@/utils'; |
215d8b
|
15 |
import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog'; |
190112
|
16 |
import { useI18n } from '/@/hooks/web/useI18n'; |
50f94b
|
17 |
import { joinTimestamp, formatRequestDate } from './helper'; |
2f6253
|
18 |
|
737b1b
|
19 |
const globSetting = useGlobSetting(); |
50f94b
|
20 |
const urlPrefix = globSetting.urlPrefix; |
2f6253
|
21 |
const { createMessage, createErrorModal } = useMessage(); |
陈 |
22 |
|
|
23 |
/** |
|
24 |
* @description: 数据处理,方便区分多种处理方式 |
|
25 |
*/ |
|
26 |
const transform: AxiosTransform = { |
|
27 |
/** |
b218f1
|
28 |
* @description: 处理请求数据。如果数据不是预期格式,可直接抛出错误 |
2f6253
|
29 |
*/ |
a821d9
|
30 |
transformRequestHook: (res: AxiosResponse<Result>, options: RequestOptions) => { |
962f90
|
31 |
const { t } = useI18n(); |
b6d5b0
|
32 |
const { isTransformResponse, isReturnNativeResponse } = options; |
56d8af
|
33 |
// 是否返回原生响应头 比如:需要获取响应头时使用该属性 |
Z |
34 |
if (isReturnNativeResponse) { |
|
35 |
return res; |
|
36 |
} |
2f6253
|
37 |
// 不进行任何处理,直接返回 |
陈 |
38 |
// 用于页面代码可能需要直接获取code,data,message这些信息时开启 |
b6d5b0
|
39 |
if (!isTransformResponse) { |
2f6253
|
40 |
return res.data; |
陈 |
41 |
} |
|
42 |
// 错误的时候返回 |
|
43 |
|
|
44 |
const { data } = res; |
|
45 |
if (!data) { |
|
46 |
// return '[HTTP] Request has no return value'; |
b218f1
|
47 |
throw new Error(t('sys.api.apiRequestFailed')); |
2f6253
|
48 |
} |
陈 |
49 |
// 这里 code,result,message为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式 |
|
50 |
const { code, result, message } = data; |
|
51 |
|
|
52 |
// 这里逻辑可以根据项目进行修改 |
|
53 |
const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS; |
b69dcd
|
54 |
if (hasSuccess) { |
e83cb0
|
55 |
return result; |
2f6253
|
56 |
} |
b69dcd
|
57 |
|
无 |
58 |
// 在此处根据自己项目的实际情况对不同的code执行不同的操作 |
|
59 |
// 如果不希望中断当前请求,请return数据,否则直接抛出异常即可 |
49b66e
|
60 |
let timeoutMsg = ''; |
b69dcd
|
61 |
switch (code) { |
无 |
62 |
case ResultEnum.TIMEOUT: |
49b66e
|
63 |
timeoutMsg = t('sys.api.timeoutMessage'); |
49f39d
|
64 |
break; |
b69dcd
|
65 |
default: |
无 |
66 |
if (message) { |
49b66e
|
67 |
timeoutMsg = message; |
b69dcd
|
68 |
} |
2f6253
|
69 |
} |
49b66e
|
70 |
|
X |
71 |
// errorMessageMode=‘modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误 |
|
72 |
// errorMessageMode='none' 一般是调用时明确表示不希望自动弹出错误提示 |
|
73 |
if (options.errorMessageMode === 'modal') { |
|
74 |
createErrorModal({ title: t('sys.api.errorTip'), content: timeoutMsg }); |
|
75 |
} else if (options.errorMessageMode === 'message') { |
|
76 |
createMessage.error(timeoutMsg); |
|
77 |
} |
|
78 |
|
|
79 |
throw new Error(timeoutMsg || t('sys.api.apiRequestFailed')); |
2f6253
|
80 |
}, |
陈 |
81 |
|
|
82 |
// 请求之前处理config |
|
83 |
beforeRequestHook: (config, options) => { |
996f2f
|
84 |
const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true, urlPrefix } = options; |
2f6253
|
85 |
|
陈 |
86 |
if (joinPrefix) { |
50f94b
|
87 |
config.url = `${urlPrefix}${config.url}`; |
2f6253
|
88 |
} |
陈 |
89 |
|
|
90 |
if (apiUrl && isString(apiUrl)) { |
|
91 |
config.url = `${apiUrl}${config.url}`; |
|
92 |
} |
ac1a36
|
93 |
const params = config.params || {}; |
49f39d
|
94 |
const data = config.data || false; |
无 |
95 |
formatDate && data && !isString(data) && formatRequestDate(data); |
6b3195
|
96 |
if (config.method?.toUpperCase() === RequestEnum.GET) { |
ac1a36
|
97 |
if (!isString(params)) { |
c96002
|
98 |
// 给 get 请求加上时间戳参数,避免从缓存中拿数据。 |
50f94b
|
99 |
config.params = Object.assign(params || {}, joinTimestamp(joinTime, false)); |
2f6253
|
100 |
} else { |
陈 |
101 |
// 兼容restful风格 |
50f94b
|
102 |
config.url = config.url + params + `${joinTimestamp(joinTime, true)}`; |
34c09f
|
103 |
config.params = undefined; |
2f6253
|
104 |
} |
陈 |
105 |
} else { |
ac1a36
|
106 |
if (!isString(params)) { |
V |
107 |
formatDate && formatRequestDate(params); |
49f39d
|
108 |
if (Reflect.has(config, 'data') && config.data && Object.keys(config.data).length > 0) { |
无 |
109 |
config.data = data; |
|
110 |
config.params = params; |
|
111 |
} else { |
|
112 |
// 非GET请求如果没有提供data,则将params视为data |
|
113 |
config.data = params; |
|
114 |
config.params = undefined; |
|
115 |
} |
2f6253
|
116 |
if (joinParamsToUrl) { |
49f39d
|
117 |
config.url = setObjToUrlParams( |
无 |
118 |
config.url as string, |
56a966
|
119 |
Object.assign({}, config.params, config.data), |
49f39d
|
120 |
); |
2f6253
|
121 |
} |
陈 |
122 |
} else { |
|
123 |
// 兼容restful风格 |
ac1a36
|
124 |
config.url = config.url + params; |
34c09f
|
125 |
config.params = undefined; |
2f6253
|
126 |
} |
陈 |
127 |
} |
|
128 |
return config; |
|
129 |
}, |
|
130 |
|
|
131 |
/** |
|
132 |
* @description: 请求拦截器处理 |
|
133 |
*/ |
b6d5b0
|
134 |
requestInterceptors: (config, options) => { |
2f6253
|
135 |
// 请求之前处理config |
b7ce74
|
136 |
const token = getToken(); |
d509e8
|
137 |
if (token && (config as Recordable)?.requestOptions?.withToken !== false) { |
2f6253
|
138 |
// jwt token |
b6d5b0
|
139 |
config.headers.Authorization = options.authenticationScheme |
V |
140 |
? `${options.authenticationScheme} ${token}` |
|
141 |
: token; |
2f6253
|
142 |
} |
陈 |
143 |
return config; |
|
144 |
}, |
|
145 |
|
|
146 |
/** |
49b66e
|
147 |
* @description: 响应拦截器处理 |
X |
148 |
*/ |
|
149 |
responseInterceptors: (res: AxiosResponse<any>) => { |
|
150 |
return res; |
|
151 |
}, |
|
152 |
|
|
153 |
/** |
2f6253
|
154 |
* @description: 响应错误处理 |
陈 |
155 |
*/ |
|
156 |
responseInterceptorsCatch: (error: any) => { |
962f90
|
157 |
const { t } = useI18n(); |
215d8b
|
158 |
const errorLogStore = useErrorLogStoreWithOut(); |
V |
159 |
errorLogStore.addAjaxErrorInfo(error); |
49b66e
|
160 |
const { response, code, message, config } = error || {}; |
X |
161 |
const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none'; |
de5bf7
|
162 |
const msg: string = response?.data?.error?.message ?? ''; |
V |
163 |
const err: string = error?.toString?.() ?? ''; |
49b66e
|
164 |
let errMessage = ''; |
X |
165 |
|
2f6253
|
166 |
try { |
陈 |
167 |
if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) { |
49b66e
|
168 |
errMessage = t('sys.api.apiTimeoutMessage'); |
2f6253
|
169 |
} |
6b3195
|
170 |
if (err?.includes('Network Error')) { |
49b66e
|
171 |
errMessage = t('sys.api.networkExceptionMsg'); |
X |
172 |
} |
|
173 |
|
|
174 |
if (errMessage) { |
|
175 |
if (errorMessageMode === 'modal') { |
|
176 |
createErrorModal({ title: t('sys.api.errorTip'), content: errMessage }); |
|
177 |
} else if (errorMessageMode === 'message') { |
|
178 |
createMessage.error(errMessage); |
|
179 |
} |
|
180 |
return Promise.reject(error); |
2f6253
|
181 |
} |
陈 |
182 |
} catch (error) { |
|
183 |
throw new Error(error); |
|
184 |
} |
49b66e
|
185 |
|
X |
186 |
checkStatus(error?.response?.status, msg, errorMessageMode); |
661db0
|
187 |
return Promise.reject(error); |
2f6253
|
188 |
}, |
陈 |
189 |
}; |
|
190 |
|
|
191 |
function createAxios(opt?: Partial<CreateAxiosOptions>) { |
|
192 |
return new VAxios( |
|
193 |
deepMerge( |
|
194 |
{ |
b6d5b0
|
195 |
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes |
V |
196 |
// authentication schemes,e.g: Bearer |
|
197 |
// authenticationScheme: 'Bearer', |
|
198 |
authenticationScheme: '', |
2f6253
|
199 |
timeout: 10 * 1000, |
陈 |
200 |
// 基础接口地址 |
61d4ef
|
201 |
// baseURL: globSetting.apiUrl, |
996f2f
|
202 |
|
2f6253
|
203 |
headers: { 'Content-Type': ContentTypeEnum.JSON }, |
f646e3
|
204 |
// 如果是form-data格式 |
V |
205 |
// headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED }, |
2f6253
|
206 |
// 数据处理方式 |
陈 |
207 |
transform, |
|
208 |
// 配置项,下面的选项都可以在独立的接口请求中覆盖 |
|
209 |
requestOptions: { |
|
210 |
// 默认将prefix 添加到url |
|
211 |
joinPrefix: true, |
56d8af
|
212 |
// 是否返回原生响应头 比如:需要获取响应头时使用该属性 |
Z |
213 |
isReturnNativeResponse: false, |
2f6253
|
214 |
// 需要对返回数据进行处理 |
b6d5b0
|
215 |
isTransformResponse: true, |
2f6253
|
216 |
// post请求的时候添加参数到url |
陈 |
217 |
joinParamsToUrl: false, |
|
218 |
// 格式化提交参数时间 |
|
219 |
formatDate: true, |
|
220 |
// 消息提示类型 |
4ce1d5
|
221 |
errorMessageMode: 'message', |
2f6253
|
222 |
// 接口地址 |
陈 |
223 |
apiUrl: globSetting.apiUrl, |
7df9b5
|
224 |
// 接口拼接地址 |
L |
225 |
urlPrefix: urlPrefix, |
f646e3
|
226 |
// 是否加入时间戳 |
V |
227 |
joinTime: true, |
3b8ca4
|
228 |
// 忽略重复请求 |
V |
229 |
ignoreCancelToken: true, |
c99cf5
|
230 |
// 是否携带token |
无 |
231 |
withToken: true, |
2f6253
|
232 |
}, |
陈 |
233 |
}, |
56a966
|
234 |
opt || {}, |
V |
235 |
), |
2f6253
|
236 |
); |
陈 |
237 |
} |
|
238 |
export const defHttp = createAxios(); |
|
239 |
|
|
240 |
// other api url |
|
241 |
// export const otherHttp = createAxios({ |
|
242 |
// requestOptions: { |
|
243 |
// apiUrl: 'xxx', |
7df9b5
|
244 |
// urlPrefix: 'xxx', |
2f6253
|
245 |
// }, |
陈 |
246 |
// }); |