XMLHttpRequest接受流式数据请求封装

309 阅读1分钟

1690511406864.jpg

vue3基于vant封装XMLHttpRequest 实现流式数据接收、请求超时处理、请求中止处理、二次请求处理、异常处理。

import { Toast } from "vant";
import { getUrlConfig, storage, SortParams } from "@/utils";

export class XHRRequest {
  constructor() {
    this.url = "";
    this.method = "";
    this.callBackFn = null;
    this.successFn = null;
    this.failFn = null;
    this.timoutFn = null;

    this.againFn = null;
    this.timer = null;
    this.timeoutNum = 0;
    this.token = storage.get("token");
    this.source = "h5Teacher";
    this.hasStart = false; // 流式返回是否继续
    this.isAbort = 0; // 是否终止 0 没有 1有

    this.xhr = null;
  }
  initAjax(url, params, callBackFn, successFn, failFn, againFn) {
    this.url = url;
    this.params = {
      ...params,
      source: this.source,
      token: this.token,
    };
    this.timeoutNum = 0;
    this.callBackFn = callBackFn;
    this.successFn = successFn;
    this.failFn = failFn;
    this.againFn = againFn;
    this.xhr = new XMLHttpRequest();
    this.xhr.open(
      "GET",
      `${getUrlConfig().zhujiaoDomain}${url}?${SortParams(this.params)}`,
      true,
    );
    this.xhr.addEventListener("readystatechange", () => {
      let { xhr } = this;
      if (xhr.readyState === 3 && xhr.status === 200) {
        this.hasStart = true;
        this.callBackFn && this.callBackFn(xhr.responseText);
      } else if (xhr.readyState === 4 && xhr.status === 200) {
        this.successFn && this.successFn(xhr.response);
      } else if (xhr.readyState === 4 && xhr.status === 500) {
        try {
          let res = JSON.parse(xhr.response);
          // 登录失效处理
          if (res.code == 20003) {
            storage.clear();
            window.location.replace('/home')
          } else {
            this.failFn && this.failFn(res);
          }
        } catch (error) {
          Toast(xhr.responseText);
        }
      }
    });

    this.xhr.addEventListener("abort", (abort) => {
      console.log("abort", abort);
      this.clearTimer();
    });

    this.xhr.addEventListener("error", (error) => {
      console.log("error", error);
      Toast(error);
    });

    this.xhr.ontimeout = function (e) {
      // XMLHttpRequest 超时。在此做某事。
      console.log("timout");
    };
    this.xhr.send();
    if (params.requestType == 1 && this.xhr) {
      this.checkHasStart();
    }
  }

  checkHasStart() {
    this.timer = setInterval(() => {
      if (this.hasStart) {
        this.clearTimer();
      } else {
        if (this.timeoutNum >= 10) {
          this.clearTimer();
          this.xhr.abort();
          this.againFn();
        } else {
          ++this.timeoutNum;
        }
      }
    }, 1000);
  }
  clearTimer() {
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = null;
      this.timeoutNum = 0;
    }
  }
  myAbort() {
    this.xhr.abort();
    this.xhr = null;
  }
}

//--------------------------------应用--------------------------

// 终止请求
const XHRRequestAbortFn = () => {
  state.XHRRequestFn && state.XHRRequestFn.myAbort();
};

// 智能生成接口
const getDimScoreTextFn = async (requestType = 1) => {
  let params = {
    id: props.id,
    requestType,
  };

  const callBackFn = (res) => {
    state.commentText = res;
    state.showIntelligentCommentResult = true;
  };

  const successFn = (res) => {
    state.commentText = res;
    setTimeout(() => {
      state.showCursorLine = false;
    }, 400);
  };

  const failFn = () => {
    showToast(res.msg);
    clickHandle("close");
  };

  const againAjaxFn = () => {
    getDimScoreTextFn(2);
  };

  state.XHRRequestFn = new XHRRequest();

  state.XHRRequestFn.initAjax(
    API.GET_DIM_SCORE_TEXT,
    params,
    callBackFn,
    successFn,
    failFn,
    againAjaxFn,
  );
};