axios封装

116 阅读2分钟
import axios from "axios";
import { Message } from "element-ui";

/**
 * 创建 axios实例
 * baseURL 基础路径
 * timeout 超时时间,单位毫秒
 * @type {AxiosInstance}
 */
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  // timeout: 30000,
});

/**
 * 发送请求
 * @param url 请求路径
 * @param method 请求方式 默认 get
 * @param data  入参
 * @param isUploadFile 本次请求是否上传文件 true:是
 * @param responseType 用于文件下载场景 responseType = "blob"
 * @returns promise 实例
 */
const sendRequest = ({ url, method = "get", data = {}, isUploadFile = false, responseType, headers = {} } = {}) => service.request({ url, method, data, isUploadFile, responseType, headers });

// 是否开启mock模式 true:开启
const isEnableMock = false;

/**
 * @desc 开启mock处理
 * 实现方式 如 .../user/login --->>> userLogin.json (获取 public 文件目录下 userLogin.json 文件)
 * @param {}  config
 */
function enableMockHandler(config) {
  config.method = "get";
  const urlList = config.url.split("/");
  const lastUrl = urlList[urlList.length - 1];
  const url = urlList[urlList.length - 2] + lastUrl.slice(0, 1).toUpperCase() + lastUrl.slice(1);
  config.baseURL = "/";
  config.url = `/mock/${url}.json`;
}

/**
 * 下载文件(用于下载后端返回的blob流下载)
 * @param blob blob流
 * @param type 下载的文件类型
 * @param fileName 下载的文件名称
 */
function downloadFileByBlob(blob, type, fileName) {
  let url = window.URL.createObjectURL(new Blob([blob], { type }));
  let aDom = document.createElement("a");
  aDom.setAttribute("href", url);
  aDom.setAttribute("download", fileName);
  document.body.appendChild(aDom);
  aDom.click();
  document.body.removeChild(aDom);
  window.URL.revokeObjectURL(url);
}

/**
 * @desc 处理后端下载类接口返回的可能是json情况(判断依据:response.headers['content-type'])
 * @param {response}  响应拦截器的 response
 * @return resolve:接口返回的是文件流  reject:接口返回的是json
 */
function judgeErrorByResponseType(response) {
  return new Promise((resolve, reject) => {
    if (response.headers["content-type"].includes("json")) {
      const { data } = response;
      const reader = new FileReader();
      reader.onload = () => {
        const { result } = reader;
        const res = JSON.parse(result);
        reject(res);
      };
      reader.onerror = (err) => {
        reject(err);
      };
      reader.readAsText(data);
    } else {
      resolve();
    }
  });
}

/**
 * @desc 请求拦截器
 */
service.interceptors.request.use(
  (config) => {
    if (process.env.NODE_ENV && process.env.NODE_ENV.toLowerCase() === "development" && isEnableMock) {
      enableMockHandler(config);
    }
    const token = window.vm.$store.state.token;
    if (token) {
      config.headers.Authorization = token;
    }
    if (["get", "delete", "head"].includes(config.method)) {
      config.params = config.data;
    }
    if (config.isUploadFile) {
      config.headers["content-type"] = "multipart/form-data";
    }
    return config;
  },
  (e) => {
    console.error("interceptors.request is error", e);
    Message.error("请求错误");
    return Promise.reject(e);
  }
);
// 业务错误消息提示实例
let bizErrorMsgInstance = null;
// 业务错误码
let errorCode = "";
// http错误消息提示实例
let httpErrorMsgInstance = null;
// status错误消息提示实例
let statusErrorMsgInstance = null;

/**
 * @desc 响应拦截器
 * 服务器需要设置
 * response.setHeader("Access-Control-Expose-Headers", "Content-Disposition")
 * response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
 */
service.interceptors.response.use(
  async (response) => {
    const {
      status,
      statusText,
      data: { data, message, code, promptLevel },
      config,
      headers: { "content-disposition": contentDisposition, "content-type": contentType },
    } = response;
    if (status !== 200) {
      if (!statusErrorMsgInstance) {
        statusErrorMsgInstance = Message.error({ message: statusText, duration: 3000 });
        setTimeout(() => {
          statusErrorMsgInstance = null;
        }, 3100);
      }
      return Promise.reject(statusText);
    }
    // 处理下载文件的响应
    if (config.responseType === "blob") {
      // 处理后端下载类接口返回的可能是json数据
      await judgeErrorByResponseType(response).catch(({ code, message }) => {
        Message.error({ message, duration: 3000 });
        return Promise.reject({ code, message });
      });
      let fileName = "";
      try {
        fileName = contentDisposition.slice(contentDisposition.lastIndexOf(";")).split("=")[1];
      } catch (error) {
        console.error("error", error);
      }
      return downloadFileByBlob(response.data, contentType, fileName);
    }
    // 非成功业务状态码
    if (code !== "000000") {
      if (promptLevel?.toUpperCase() === "POP") {
        // 提示错误期间 出现相同错误就不要再提示了
        if (!bizErrorMsgInstance || !(code === errorCode)) {
          errorCode = code;
          bizErrorMsgInstance = Message.error({ message, duration: 3000 });
          // 及时清除错误实例 方便下次再次用到该提示
          setTimeout(() => {
            bizErrorMsgInstance = null;
          }, 3100);
        }
      }
      return Promise.reject({ message, code, data });
    }
    return data;
  },
  (error) => {
    const responseType = error?.config?.responseType ?? "json";
    if (responseType === "blob") {
      Message.error({ message: "下载失败", duration: 3000 });
      return Promise.reject(error.message);
    }
    if (!httpErrorMsgInstance) {
      httpErrorMsgInstance = Message.error({
        message: "请求出错,请稍候重试",
        duration: 3000,
      });
      setTimeout(() => {
        httpErrorMsgInstance = null;
      }, 3100);
    }
    return Promise.reject(error.message);
  }
);

export default sendRequest;