123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- import Axios, {
- AxiosRequestConfig,
- CancelTokenStatic,
- AxiosInstance,
- Canceler
- } from "axios"
- import NProgress from "../progress"
- import { genConfig } from "./config"
- import { transformConfigByMethod } from "./utils"
- import {
- cancelTokenType,
- RequestMethods,
- EnclosureHttpRequestConfig,
- EnclosureHttpResoponse,
- EnclosureHttpError
- } from "./types.d"
- class EnclosureHttp {
- constructor() {
- this.httpInterceptorsRequest()
- this.httpInterceptorsResponse()
- }
- // 初始化配置对象
- private static initConfig: EnclosureHttpRequestConfig = {};
- // 保存当前Axios实例对象
- private static axiosInstance: AxiosInstance = Axios.create(genConfig());
- // 保存 EnclosureHttp实例
- private static EnclosureHttpInstance: EnclosureHttp
- // axios取消对象
- private CancelToken: CancelTokenStatic = Axios.CancelToken;
- // 取消的凭证数组
- private sourceTokenList: Array<cancelTokenType> = [];
- // 记录当前这一次cancelToken的key
- private currentCancelTokenKey = "";
- private beforeRequestCallback: EnclosureHttpRequestConfig["beforeRequestCallback"] = undefined;
- private beforeResponseCallback: EnclosureHttpRequestConfig["beforeResponseCallback"] = undefined;
- public get cancelTokenList(): Array<cancelTokenType> {
- return this.sourceTokenList
- }
- // eslint-disable-next-line class-methods-use-this
- public set cancelTokenList(value) {
- throw new Error("cancelTokenList不允许赋值")
- }
- /**
- * @description 私有构造不允许实例化
- * @returns void 0
- */
- // constructor() {}
- /**
- * @description 生成唯一取消key
- * @param config axios配置
- * @returns string
- */
- // eslint-disable-next-line class-methods-use-this
- private genUniqueKey(config: EnclosureHttpRequestConfig): string {
- return `${config.url}--${JSON.stringify(config.data)}`
- }
- /**
- * @description 取消重复请求
- * @returns void 0
- */
- private cancelRepeatRequest(): void {
- const temp: { [key: string]: boolean } = {}
- this.sourceTokenList = this.sourceTokenList.reduce<Array<cancelTokenType>>(
- (res: Array<cancelTokenType>, cancelToken: cancelTokenType) => {
- const { cancelKey, cancelExecutor } = cancelToken
- if (!temp[cancelKey]) {
- temp[cancelKey] = true
- res.push(cancelToken)
- } else {
- cancelExecutor()
- }
- return res
- },
- []
- )
- }
- /**
- * @description 删除指定的CancelToken
- * @returns void 0
- */
- private deleteCancelTokenByCancelKey(cancelKey: string): void {
- this.sourceTokenList =
- this.sourceTokenList.length < 1
- ? this.sourceTokenList.filter(
- cancelToken => cancelToken.cancelKey !== cancelKey
- )
- : []
- }
- /**
- * @description 拦截请求
- * @returns void 0
- */
- private httpInterceptorsRequest(): void {
- EnclosureHttp.axiosInstance.interceptors.request.use(
- (config: EnclosureHttpRequestConfig) => {
- const $config = config
- NProgress.start() // 每次切换页面时,调用进度条
- const cancelKey = this.genUniqueKey($config)
- $config.cancelToken = new this.CancelToken((cancelExecutor: (cancel: any) => void) => {
- this.sourceTokenList.push({ cancelKey, cancelExecutor })
- })
- this.cancelRepeatRequest()
- this.currentCancelTokenKey = cancelKey
- // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉
- if (typeof this.beforeRequestCallback === "function") {
- this.beforeRequestCallback($config)
- this.beforeRequestCallback = undefined
- return $config
- }
- if (EnclosureHttp.initConfig.beforeRequestCallback) {
- EnclosureHttp.initConfig.beforeRequestCallback($config)
- return $config
- }
- return $config
- },
- error => {
- return Promise.reject(error)
- }
- )
- }
- /**
- * @description 清空当前cancelTokenList
- * @returns void 0
- */
- public clearCancelTokenList(): void {
- this.sourceTokenList.length = 0
- }
- /**
- * @description 拦截相应
- * @returns void 0
- */
- private httpInterceptorsResponse(): void {
- const instance = EnclosureHttp.axiosInstance
- instance.interceptors.response.use(
- (response: EnclosureHttpResoponse) => {
- // 请求每次成功一次就删除当前canceltoken标记
- const cancelKey = this.genUniqueKey(response.config)
- this.deleteCancelTokenByCancelKey(cancelKey)
- // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉
- if (typeof this.beforeResponseCallback === "function") {
- this.beforeResponseCallback(response)
- this.beforeResponseCallback = undefined
- return response.data
- }
- if (EnclosureHttp.initConfig.beforeResponseCallback) {
- EnclosureHttp.initConfig.beforeResponseCallback(response)
- return response.data
- }
- NProgress.done()
- return response.data
- },
- (error: EnclosureHttpError) => {
- const $error = error
- // 判断当前的请求中是否在 取消token数组理存在,如果存在则移除(单次请求流程)
- if (this.currentCancelTokenKey) {
- const haskey = this.sourceTokenList.filter(
- cancelToken => cancelToken.cancelKey === this.currentCancelTokenKey
- ).length
- if (haskey) {
- this.sourceTokenList = this.sourceTokenList.filter(
- cancelToken =>
- cancelToken.cancelKey !== this.currentCancelTokenKey
- )
- this.currentCancelTokenKey = ""
- }
- }
- $error.isCancelRequest = Axios.isCancel($error)
- // 所有的响应异常 区分来源为取消请求/非取消请求
- return Promise.reject($error)
- }
- )
- }
- public request<T>(
- method: RequestMethods,
- url: string,
- param?: AxiosRequestConfig,
- axiosConfig?: EnclosureHttpRequestConfig,
- ): Promise<T> {
- const config = transformConfigByMethod(param, {
- method,
- url,
- ...axiosConfig
- } as EnclosureHttpRequestConfig)
- // 单独处理自定义请求/响应回掉
- if (axiosConfig?.beforeRequestCallback) {
- this.beforeRequestCallback = axiosConfig.beforeRequestCallback
- }
- if (axiosConfig?.beforeResponseCallback) {
- this.beforeResponseCallback = axiosConfig.beforeResponseCallback
- }
- return new Promise((resolve, reject) => {
- EnclosureHttp.axiosInstance.request(config)
- .then((response: EnclosureHttpResoponse) => {
- resolve(response)
- })
- .catch((error: any) => {
- reject(error)
- })
- })
- }
- public post<T>(
- url: string,
- params?: T,
- config?: EnclosureHttpRequestConfig
- ): Promise<T> {
- return this.request<T>("post", url, params, config)
- }
- public get<T>(
- url: string,
- params?: T,
- config?: EnclosureHttpRequestConfig
- ): Promise<T> {
- return this.request<T>("get", url, params, config)
- }
- }
- export default EnclosureHttp
|