setup.ts 6.9 KB

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