• JS


    import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
    
    export interface HttpOption {
      throttle?: {
        wait: number;
        mergeConfig: (
          previousConfig: AxiosRequestConfig,
          currentConfig: AxiosRequestConfig
        ) => AxiosRequestConfig;
        assignResponse: (
          response: AxiosResponse<any>,
          config: AxiosRequestConfig
        ) => AxiosResponse<any>;
      };
      cache?: {
        set: (config: AxiosRequestConfig, response: AxiosResponse<any>) => void;
        get: (config: AxiosRequestConfig) => any;
      };
    }
    
    interface HttpRequest {
      resolve: (
        value: AxiosResponse<any> | PromiseLike<AxiosResponse<any>>
      ) => void;
      reject: (reason?: any) => void;
      config: AxiosRequestConfig;
    }
    
    export default class Http {
      response;
      request;
      // 以 method 和 url 区分请求类型,保存不同类型的配置项
      optionList: Partial<{ [key: string]: HttpOption }> = {};
      // 节流请求的 timeout 列表
      timeoutList: Partial<{ [key: string]: number }> = {};
      // 节流请求的临时列表
      throttleList: Partial<{ [key: string]: HttpRequest[] }> = {};
      // 真实请求列表
      requestList: Partial<{ [key: string]: HttpRequest[] }> = {};
      constructor(defaultConfig?: AxiosRequestConfig) {
        this.response = axios.create(defaultConfig);
        this.request = axios.create(defaultConfig);
    
        this.request.interceptors.request.use(config => {
          if (!config.url) return config;
          const typeKey = this.getTypeKey(config.url, config.method);
          const option = this.optionList[typeKey];
    
          // 有缓存的话直接直接返回缓存,并且不再通过转换函数;
          const cache = option?.cache?.get(config);
          if (cache)
            return {
              ...config,
              transformRequest(data) {
                return data;
              },
              adapter: () =>
                new Promise<any>(resolve =>
                  resolve({
                    data: cache,
                    status: 200,
                    statusText: "OK", // 这里应该需要根据服务器返回进行修改
                    headers: config.headers,
                    config
                  })
                )
            };
    
          // 没有缓存的请求分为节流请求和普通请求
          if (option?.throttle?.wait) {
            // 在节流时间后合并config,发起真实请求。转移节流请求列表到真实请求列表中
            if (!this.timeoutList[typeKey]) {
              this.timeoutList[typeKey] = setTimeout(() => {
                clearTimeout(this.timeoutList[typeKey]);
                delete this.timeoutList[typeKey];
                const mergeConfig = option.throttle
                  ? this.mergeConfig(typeKey, option.throttle)
                  : config;
                const mergeRequestKey = this.getKeyFromRequest(mergeConfig);
                // 多次相同的合并请求去抖动
                if (!this.requestList[mergeRequestKey]) this.response(mergeConfig);
                this.requestList[mergeRequestKey] = (
                  this.requestList[mergeRequestKey] ?? []
                ).concat(this.throttleList[typeKey] ?? []);
                delete this.throttleList[typeKey];
              }, option.throttle.wait);
            }
            return {
              ...config,
              adapter: () =>
                new Promise<any>((resolve, reject) => {
                  this.throttleList[typeKey] = (
                    this.throttleList[typeKey] ?? []
                  ).concat({
                    resolve,
                    reject,
                    config
                  });
                })
            };
          } else {
            // 发起真实请求,在请求未返回前去抖动重复的请求
            const requestKey = this.getKeyFromRequest(config);
            if (!this.requestList[requestKey]) this.response(config);
            return {
              ...config,
              adapter: () =>
                new Promise<any>((resolve, reject) => {
                  this.requestList[requestKey] = (
                    this.requestList[requestKey] ?? []
                  ).concat({
                    resolve,
                    reject,
                    config
                  });
                })
            };
          }
        });
    
        this.response.interceptors.response.use(response => {
          // 响应的 config 和请求的 config 并不相同,它是请求发起时使用的真实值。
          const config = response.config;
          const requestKey = this.getKeyFromResponse(config);
          if (!config.url) return response;
          const typeKey = this.getTypeKey(config.url, config.method);
          const option = this.optionList[typeKey];
    
          // 分配响应给请求列表中的所有请求
          this.requestList[requestKey]?.forEach(({ resolve, config }) => {
            const resolveResponse =
              option?.throttle?.assignResponse(response, config) ?? response;
            // 配置了 cache 时写入缓存
            option?.cache?.set(config, resolveResponse);
            resolve(resolveResponse);
          });
          delete this.requestList[requestKey];
          return response;
        });
      }
      // 节流请求合并config
      mergeConfig(
        typeKey: string,
        throttle: NonNullable<HttpOption["throttle"]>
      ): AxiosRequestConfig {
        return (this.throttleList[typeKey] ?? []).reduce((p, c) => {
          return throttle.mergeConfig(p, c.config);
        }, {});
      }
      // 请求阶段获取具有相同config的请求的唯一值,作为区分不同请求的key
      getKeyFromRequest(config: AxiosRequestConfig) {
        return JSON.stringify({
          ...config,
          headers: undefined,
          data: config.transformRequest
            ? Array.isArray(config.transformRequest)
              ? config.transformRequest.reduce((p, c) => {
                  return c(p, config.headers);
                }, config.data)
              : config.transformRequest(config.data, config.headers)
            : config.data,
          params: config.paramsSerializer
            ? config.paramsSerializer(config.params)
            : config.params
        });
      }
      // 响应阶段获取具有相同config的请求的唯一值,作为区分不同请求的key
      getKeyFromResponse(config: AxiosRequestConfig) {
        return JSON.stringify({
          ...config,
          headers: undefined
        });
      }
      // 获取一类请求的key,用于保存这类请求的option。
      getTypeKey(url: string, method: AxiosRequestConfig["method"]) {
        return `${method}:${url}`;
      }
      post<T>(
        url: string,
        data?: any,
        option?: HttpOption,
        config?: AxiosRequestConfig
      ) {
        this.optionList[this.getTypeKey(url, "post")] = option;
        return this.request.post<T>(url, data, config);
      }
    }
    
  • 相关阅读:
    155. 最小栈
    160. 相交链表
    PAT 1057 Stack
    PAT 1026 Table Tennis
    PAT 1017 Queueing at Bank
    PAT 1014 Waiting in Line
    PAT 1029 Median
    PAT 1016 Phone Bills
    PAT 1010 Radix
    PAT 1122 Hamiltonian Cycle
  • 原文地址:https://www.cnblogs.com/qq3279338858/p/14474707.html
Copyright © 2020-2023  润新知