core.ts 7.1 KB

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