setup.ts 6.7 KB

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