setup.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import Axios from 'axios'
  2. import { ResCode } from './constant'
  3. import { setOfflineAxios } from './offline'
  4. import type { AxiosResponse, AxiosRequestConfig } from 'axios'
  5. import { ui18n } from '@/lang'
  6. export type ResErrorHandler = <D, T extends ResData<D>>(response: AxiosResponse<T>, data?: T) => void
  7. export type ReqErrorHandler = <T>(err: Error, response: AxiosRequestConfig<T>) => void
  8. export type ResData<T> = { code: ResCode, message: string, data: T, msg: string }
  9. export type Hook = {
  10. before?: (config: AxiosRequestConfig) => void
  11. after?: (config: AxiosRequestConfig) => void
  12. }
  13. export const axiosFactory = () => {
  14. const axiosRaw = Axios.create()
  15. const axiosConfig = {
  16. token: localStorage.getItem('token'),
  17. unTokenSet: [] as string[],
  18. unReqErrorSet: [] as string[],
  19. unResErrorSet: [] as string[],
  20. resErrorHandler: [] as ResErrorHandler[],
  21. reqErrorHandler: [] as ReqErrorHandler[],
  22. unLoadingSet: [] as string[],
  23. hook: [] as Hook[]
  24. }
  25. type AxiosConfig = typeof axiosConfig
  26. type ExponseApi<K extends keyof AxiosConfig> =
  27. { set: (val: AxiosConfig[K]) => void }
  28. & (AxiosConfig[K] extends Array<any>
  29. ? {
  30. add: (...val: AxiosConfig[K]) => void,
  31. del: (...val: AxiosConfig[K]) => void
  32. }
  33. : { del: () => void })
  34. const getExponseApi = <K extends keyof AxiosConfig>(key: K): ExponseApi<K> => {
  35. let axiosObj = axiosConfig[key] as any[]
  36. const apis: any = {
  37. set (val: AxiosConfig[K]) {
  38. axiosObj = axiosConfig[key] = val as any
  39. }
  40. }
  41. if (Array.isArray(axiosObj)) {
  42. apis.add = (...val: any[]) => {
  43. axiosObj.push(...val)
  44. }
  45. apis.del = (...val: any[]) => {
  46. if (val) {
  47. apis.set(axiosObj.filter((item: any) => !val?.includes(item)) as any)
  48. } else {
  49. axiosObj.length = 0
  50. }
  51. }
  52. } else {
  53. apis.del = () => {
  54. axiosConfig[key] = undefined as any
  55. }
  56. }
  57. return apis
  58. }
  59. const getToken = () => axiosConfig.token
  60. const setToken = (token: string) => {
  61. localStorage.setItem('token', token)
  62. axiosConfig.token = token
  63. }
  64. const delToken = () => {
  65. localStorage.removeItem('token')
  66. axiosConfig.token = null
  67. }
  68. const {
  69. set: setUnsetTokenURLS,
  70. add: addUnsetTokenURLS,
  71. del: delUnsetTokenURLS
  72. } = getExponseApi('unTokenSet')
  73. const {
  74. set: setResErrorHandler,
  75. add: addResErrorHandler,
  76. del: delResErrorHandler
  77. } = getExponseApi('resErrorHandler')
  78. const {
  79. set: setUnsetReqErrorURLS,
  80. add: addUnsetReqErrorURLS,
  81. del: delUnsetReqErrorURLS
  82. } = getExponseApi('unReqErrorSet')
  83. const {
  84. set: setReqErrorHandler,
  85. add: addReqErrorHandler,
  86. del: delReqErrorHandler
  87. } = getExponseApi('reqErrorHandler')
  88. const {
  89. set: setUnsetResErrorURLS,
  90. add: addUnsetResErrorURLS,
  91. del: delUnsetResErrorURLS
  92. } = getExponseApi('unResErrorSet')
  93. const {
  94. set: setHook,
  95. add: addHook,
  96. del: delHook
  97. } = getExponseApi('hook')
  98. const setDefaultURI = (url: string) => {
  99. axiosRaw.defaults.baseURL = url
  100. }
  101. const matchURL = (urls: string[], config: AxiosRequestConfig<any>) =>
  102. config && config.url && urls.includes(config.url)
  103. const callErrorHandler = (key: 'req' | 'res', ...args: any[]) => {
  104. Promise.resolve()
  105. .then(() => {
  106. const api = `${key}ErrorHandler`
  107. ;(axiosConfig as any)[api].forEach((handler: any) => handler(...args))
  108. })
  109. }
  110. axiosRaw.interceptors.request.use(
  111. config => {
  112. for (const hook of axiosConfig.hook) {
  113. hook.before && hook.before(config)
  114. }
  115. if (!matchURL(axiosConfig.unTokenSet, config)) {
  116. if (!axiosConfig.token) {
  117. if (!offline && !matchURL(axiosConfig.unReqErrorSet, config)) {
  118. const error = new Error(ui18n.t('resCode.4008'))
  119. callErrorHandler('req', error, config)
  120. throw error
  121. }
  122. } else {
  123. config.headers = {
  124. ...config.headers,
  125. token: axiosConfig.token
  126. }
  127. }
  128. }
  129. return config
  130. }
  131. )
  132. offline && setOfflineAxios(axiosRaw)
  133. axiosRaw.interceptors.response.use(
  134. (response: AxiosResponse<ResData<any>>) => {
  135. for (const hook of axiosConfig.hook) {
  136. hook.after && hook.after(response.config)
  137. }
  138. if (matchURL(axiosConfig.unResErrorSet, response.config)) {
  139. return response
  140. }
  141. if (response.status !== 200) {
  142. callErrorHandler('res', response)
  143. throw new Error(response.statusText)
  144. } else if (response.data.code !== ResCode.SUCCESS) {
  145. callErrorHandler('res', response, response.data)
  146. if (response.data.code === ResCode.TOKEN_INVALID) {
  147. delToken()
  148. }
  149. throw new Error(response?.data?.message)
  150. } else {
  151. return response.data.data
  152. }
  153. },
  154. (err) => {
  155. for (const hook of axiosConfig.hook) {
  156. hook.after && hook.after(err.config)
  157. }
  158. if (!matchURL(axiosConfig.unResErrorSet, err.config)) {
  159. callErrorHandler('res', err.response)
  160. }
  161. throw new Error(err.response && err.response.statusText)
  162. }
  163. )
  164. type AxiosProcess = {
  165. getUri(config?: AxiosRequestConfig): string;
  166. request<R = any, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
  167. get<R = any, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
  168. delete<R = any, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
  169. head<R = any, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
  170. options<R = any, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
  171. post<R = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
  172. put<R = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
  173. patch<R = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
  174. postForm<R = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
  175. putForm<R = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
  176. patchForm<R = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
  177. }
  178. interface AxiosInstanceProcess extends AxiosProcess {
  179. <R = any>(config: AxiosRequestConfig): Promise<R>;
  180. <R = any>(url: string, config?: AxiosRequestConfig): Promise<R>;
  181. }
  182. const axios: AxiosInstanceProcess = axiosRaw as any
  183. return {
  184. axios,
  185. getToken,
  186. setToken,
  187. delToken,
  188. setUnsetTokenURLS,
  189. addUnsetTokenURLS,
  190. delUnsetTokenURLS,
  191. setResErrorHandler,
  192. addResErrorHandler,
  193. delResErrorHandler,
  194. setUnsetReqErrorURLS,
  195. addUnsetReqErrorURLS,
  196. delUnsetReqErrorURLS,
  197. setReqErrorHandler,
  198. addReqErrorHandler,
  199. delReqErrorHandler,
  200. setUnsetResErrorURLS,
  201. addUnsetResErrorURLS,
  202. delUnsetResErrorURLS,
  203. setDefaultURI,
  204. setHook,
  205. addHook,
  206. delHook,
  207. }
  208. }
  209. export default axiosFactory