core.ts 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import Axios, {
  2. AxiosRequestConfig,
  3. CancelTokenStatic,
  4. AxiosInstance,
  5. Canceler
  6. } from "axios"
  7. import NProgress from "../progress"
  8. import { genConfig } from "./config"
  9. import { transformConfigByMethod } from "./utils"
  10. import {
  11. cancelTokenType,
  12. RequestMethods,
  13. EnclosureHttpRequestConfig,
  14. EnclosureHttpResoponse,
  15. EnclosureHttpError
  16. } from "./types.d"
  17. class EnclosureHttp {
  18. constructor() {
  19. this.httpInterceptorsRequest()
  20. this.httpInterceptorsResponse()
  21. }
  22. // 初始化配置对象
  23. private static initConfig: EnclosureHttpRequestConfig = {};
  24. // 保存当前Axios实例对象
  25. private static axiosInstance: AxiosInstance = Axios.create(genConfig());
  26. // 保存 EnclosureHttp实例
  27. private static EnclosureHttpInstance: EnclosureHttp
  28. // axios取消对象
  29. private CancelToken: CancelTokenStatic = Axios.CancelToken;
  30. // 取消的凭证数组
  31. private sourceTokenList: Array<cancelTokenType> = [];
  32. // 记录当前这一次cancelToken的key
  33. private currentCancelTokenKey = "";
  34. private beforeRequestCallback: EnclosureHttpRequestConfig["beforeRequestCallback"] = undefined;
  35. private beforeResponseCallback: EnclosureHttpRequestConfig["beforeResponseCallback"] = undefined;
  36. public get cancelTokenList(): Array<cancelTokenType> {
  37. return this.sourceTokenList
  38. }
  39. // eslint-disable-next-line class-methods-use-this
  40. public set cancelTokenList(value) {
  41. throw new Error("cancelTokenList不允许赋值")
  42. }
  43. /**
  44. * @description 私有构造不允许实例化
  45. * @returns void 0
  46. */
  47. // constructor() {}
  48. /**
  49. * @description 生成唯一取消key
  50. * @param config axios配置
  51. * @returns string
  52. */
  53. // eslint-disable-next-line class-methods-use-this
  54. private genUniqueKey(config: EnclosureHttpRequestConfig): string {
  55. return `${config.url}--${JSON.stringify(config.data)}`
  56. }
  57. /**
  58. * @description 取消重复请求
  59. * @returns void 0
  60. */
  61. private cancelRepeatRequest(): void {
  62. const temp: { [key: string]: boolean } = {}
  63. this.sourceTokenList = this.sourceTokenList.reduce<Array<cancelTokenType>>(
  64. (res: Array<cancelTokenType>, cancelToken: cancelTokenType) => {
  65. const { cancelKey, cancelExecutor } = cancelToken
  66. if (!temp[cancelKey]) {
  67. temp[cancelKey] = true
  68. res.push(cancelToken)
  69. } else {
  70. cancelExecutor()
  71. }
  72. return res
  73. },
  74. []
  75. )
  76. }
  77. /**
  78. * @description 删除指定的CancelToken
  79. * @returns void 0
  80. */
  81. private deleteCancelTokenByCancelKey(cancelKey: string): void {
  82. this.sourceTokenList =
  83. this.sourceTokenList.length < 1
  84. ? this.sourceTokenList.filter(
  85. cancelToken => cancelToken.cancelKey !== cancelKey
  86. )
  87. : []
  88. }
  89. /**
  90. * @description 拦截请求
  91. * @returns void 0
  92. */
  93. private httpInterceptorsRequest(): void {
  94. EnclosureHttp.axiosInstance.interceptors.request.use(
  95. (config: EnclosureHttpRequestConfig) => {
  96. const $config = config
  97. NProgress.start() // 每次切换页面时,调用进度条
  98. const cancelKey = this.genUniqueKey($config)
  99. $config.cancelToken = new this.CancelToken((cancelExecutor: (cancel: any) => void) => {
  100. this.sourceTokenList.push({ cancelKey, cancelExecutor })
  101. })
  102. this.cancelRepeatRequest()
  103. this.currentCancelTokenKey = cancelKey
  104. // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉
  105. if (typeof this.beforeRequestCallback === "function") {
  106. this.beforeRequestCallback($config)
  107. this.beforeRequestCallback = undefined
  108. return $config
  109. }
  110. if (EnclosureHttp.initConfig.beforeRequestCallback) {
  111. EnclosureHttp.initConfig.beforeRequestCallback($config)
  112. return $config
  113. }
  114. return $config
  115. },
  116. error => {
  117. return Promise.reject(error)
  118. }
  119. )
  120. }
  121. /**
  122. * @description 清空当前cancelTokenList
  123. * @returns void 0
  124. */
  125. public clearCancelTokenList(): void {
  126. this.sourceTokenList.length = 0
  127. }
  128. /**
  129. * @description 拦截相应
  130. * @returns void 0
  131. */
  132. private httpInterceptorsResponse(): void {
  133. const instance = EnclosureHttp.axiosInstance
  134. instance.interceptors.response.use(
  135. (response: EnclosureHttpResoponse) => {
  136. // 请求每次成功一次就删除当前canceltoken标记
  137. const cancelKey = this.genUniqueKey(response.config)
  138. this.deleteCancelTokenByCancelKey(cancelKey)
  139. // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉
  140. if (typeof this.beforeResponseCallback === "function") {
  141. this.beforeResponseCallback(response)
  142. this.beforeResponseCallback = undefined
  143. return response.data
  144. }
  145. if (EnclosureHttp.initConfig.beforeResponseCallback) {
  146. EnclosureHttp.initConfig.beforeResponseCallback(response)
  147. return response.data
  148. }
  149. NProgress.done()
  150. return response.data
  151. },
  152. (error: EnclosureHttpError) => {
  153. const $error = error
  154. // 判断当前的请求中是否在 取消token数组理存在,如果存在则移除(单次请求流程)
  155. if (this.currentCancelTokenKey) {
  156. const haskey = this.sourceTokenList.filter(
  157. cancelToken => cancelToken.cancelKey === this.currentCancelTokenKey
  158. ).length
  159. if (haskey) {
  160. this.sourceTokenList = this.sourceTokenList.filter(
  161. cancelToken =>
  162. cancelToken.cancelKey !== this.currentCancelTokenKey
  163. )
  164. this.currentCancelTokenKey = ""
  165. }
  166. }
  167. $error.isCancelRequest = Axios.isCancel($error)
  168. // 所有的响应异常 区分来源为取消请求/非取消请求
  169. return Promise.reject($error)
  170. }
  171. )
  172. }
  173. public request<T>(
  174. method: RequestMethods,
  175. url: string,
  176. param?: AxiosRequestConfig,
  177. axiosConfig?: EnclosureHttpRequestConfig,
  178. ): Promise<T> {
  179. const config = transformConfigByMethod(param, {
  180. method,
  181. url,
  182. ...axiosConfig
  183. } as EnclosureHttpRequestConfig)
  184. // 单独处理自定义请求/响应回掉
  185. if (axiosConfig?.beforeRequestCallback) {
  186. this.beforeRequestCallback = axiosConfig.beforeRequestCallback
  187. }
  188. if (axiosConfig?.beforeResponseCallback) {
  189. this.beforeResponseCallback = axiosConfig.beforeResponseCallback
  190. }
  191. return new Promise((resolve, reject) => {
  192. EnclosureHttp.axiosInstance.request(config)
  193. .then((response: EnclosureHttpResoponse) => {
  194. resolve(response)
  195. })
  196. .catch((error: any) => {
  197. reject(error)
  198. })
  199. })
  200. }
  201. public post<T>(
  202. url: string,
  203. params?: T,
  204. config?: EnclosureHttpRequestConfig
  205. ): Promise<T> {
  206. return this.request<T>("post", url, params, config)
  207. }
  208. public get<T>(
  209. url: string,
  210. params?: T,
  211. config?: EnclosureHttpRequestConfig
  212. ): Promise<T> {
  213. return this.request<T>("get", url, params, config)
  214. }
  215. }
  216. export default EnclosureHttp