封装axios

100 阅读2分钟

随着项目规模增大,如果每发起一次HTTP请求,就要把这些比如设置超时时间、设置请求头、根据项目环境判断使用哪个请求地址、错误处理等等操作,都需要写一遍

这种重复劳动不仅浪费时间,而且让代码变得冗余不堪,难以维护。为了提高我们的代码质量,我们应该在项目中二次封装一下 axios 再使用

请求步骤:发起请求--请求拦截(进行请求头等信息处理)--获取到数据--响应拦截(对返回信息进行处理判断)--得到处理后的数据 (axios中文文档 (javasoho.com))

import axios from "axios";

import store from "../store";

import { Message, MessageBox } from "element-ui";

import db from "@/utils/localstorage";

import { Base64 } from "js-base64";

  


// 请求添加条件,如token
axios.interceptors.request.use(

  config => {

    const isToken =

      config.headers["X-isToken"] === false

        ? config.headers["X-isToken"]

        : true;

    const token = db.get("TOKEN", "");

    if (token && isToken) {

      config.headers.token = "Bearer " + token;

    }
//以上在请求拦截中对header进行处理
  


    const isTenant =

      config.headers["X-isTenant"] === false

        ? config.headers["X-isTenant"]

        : true;

    if (isTenant && process.env.VUE_APP_IS_MULTI_TENANT_TYPE !== "NONE") {

      config.headers.tenant = db.get("TENANT", "");

    }

    const clientId = process.env.VUE_APP_CLIENT_ID;

    const clientSecret = process.env.VUE_APP_CLIENT_SECRET;

    config.headers["Authorization"] = `Basic ${Base64.encode(

      `${clientId}:${clientSecret}`

    )}`;
    //设置内容类型
    config.headers["Content-Type"] = "application/json";

    }

    return config;

  },

  error => {

    return Promise.reject(error);

  }

);

  


// 接口返回处理

axios.interceptors.response.use(

  response => {

    return response;

  },

  error => {

    return Promise.reject(error);

  }

);

  

//也可以放在响应拦截中
function handleError(error, reject, opts) {

  // debugger // 方便network TODO: 20210910 开发暂时停止

  let isAlert = opts.custom ? opts.custom["isAlert"] : true;

  isAlert = isAlert === undefined ? true : isAlert;

  if (isAlert) {

    if (error.code === "ECONNABORTED") {

      Message({

        message: "请求超时"

      });

    } else if (error.response && error.response.data) {

      const resData = error.response.data;
      //对状态码进行判断

      if (error.response.status === 403 || error.response.status === 401) {

        MessageBox.alert(resData.msg || "登录已失效,请重新登录", "提醒", {

          confirmButtonText: "确定",

          callback: () => {

            db.clear();

            window.location.hash = "/login";

          }

        });

      } else if (error.response.status === 500) {

        Message({

          message: error.response.data

        });

      } else {
      //对返回的code进行判断

        const resData = error.response.data;

        if (

          resData.code === 40000 ||

          resData.code === 40001 ||

          resData.code === 40002 ||

          resData.code === 40003 ||

          resData.code === 40005 ||

          resData.code === 40006 ||

          resData.code === 40008 ||

          resData.code === 40009

        ) {

          MessageBox.alert(resData.msg || resData.message, "提醒", {

            confirmButtonText: "确定",

            callback: () => {

              db.clear();

              window.location.hash = "/login";

            }

          });

        } else if (resData.msg) {

          Message({

            message: resData.msg

          });

        } else if (resData.message) {

          Message({

            message: resData.message

          });

        }

      }

    } else if (error.message) {

      Message({

        message: error.message

      });

    }

  }

  reject(error);

}

  


function handleSuccess(res, resolve, opts) {

  let isAlert = opts.custom ? opts.custom["isAlert"] : true;

  isAlert = isAlert === undefined ? true : isAlert;

  const resData = res.data;

  if (resData.isSuccess === false) {

    // 未登录

    if (

      resData.code === 40000 ||

      resData.code === 40001 ||

      resData.code === 40002 ||

      resData.code === 40003 ||

      resData.code === 40005 ||

      resData.code === 40006 ||

      resData.code === 40008

    ) {
      debugger;
      MessageBox.alert(resData.msg, "提醒", {
        confirmButtonText: "确定",
        callback: () => {
          window.location.hash = "/login";
        }
      });
    } else {
      if (isAlert) {
        Message.error(resData.msg);
      }
    }
  }
  resolve(res);
}
// http请求
const httpServer = opts => {
  // 公共参数
  const publicParams = {
    ts: Date.now()
  };
  // http默认配置
  const method = opts.method.toUpperCase();
  // baseURL
  // 开发环境: /api                 // 开发环境在 vue.config.js 中有 devServer.proxy 代理
  // 生产环境: http://IP:PORT/api   // 生产环境中 代理失效, 故需要配置绝对路径
//对请求参数进行处理
  const httpDefaultOpts = {
    method,
//baseURL根据环境不同选择不同的baseURL
    baseURL:
      process.env.VUE_APP_PROD_REQUEST_DOMAIN_PREFIX +
      process.env.VUE_APP_BASE_API,
    url: opts.url,
    responseType: opts.responseType || "",
    // timeout: (opts.custom && opts.custom["timeout"]) || 30000
    timeout: 30 * 60 * 1000 //链接请求改为30min
  };
  if (opts["meta"]) {
    httpDefaultOpts.headers = opts["meta"];
  }
//对不同的请求方法进行处理
  const dataRequest = ["PUT", "POST", "DELETE", "PATCH"];
  if (dataRequest.includes(method)) {
    httpDefaultOpts.data = opts.data || {};
    httpDefaultOpts.params = publicParams;
  } else {
    httpDefaultOpts.params = {
      ...publicParams,
      ...(opts.data || {})
    };
  }
  // formData转换
  if (opts.formData) {
    httpDefaultOpts.transformRequest = [
      data => {
        const formData = new FormData();
        if (data) {
          Object.entries(data).forEach(item => {

            formData.append(item[0], item[1]);

          });
        }
        return formData;
      }
    ];
  }

  const promise = new Promise((resolve, reject) => {

    axios(httpDefaultOpts)

      .then(response => {

        handleSuccess(response, resolve, opts);

      })

      .catch(error => {

        handleError(error, reject, opts);

      });

  });

  return promise;

};

export default httpServer;

使用:
import axiosApi from "../AxiosApi.js";

export default {
  getFirstUnitClass(data) {

    return axiosApi({

      method: "get",

      url: `receive/transferUnit/top`,

      data

    });

  },
  }
  
  在需要使用当前接口的vue文件中导入此文件 request.getFirstUnitClass(params).then()

简易版:

import axios, { AxiosInstance } from 'axios';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Session } from '/@/utils/storage';
import qs from 'qs';

// 配置新建一个 axios 实例
const service: AxiosInstance = axios.create({
	baseURL: import.meta.env.VITE_API_URL,
	timeout: 50000,
	headers: { 'Content-Type': 'application/json' },
	paramsSerializer: {
		serialize(params) {
			return qs.stringify(params, { allowDots: true });
		},
	},
});

// 添加请求拦截器
service.interceptors.request.use(
	(config) => {
		// 在发送请求之前做些什么 token
		if (Session.get('token')) {
			config.headers!['Authorization'] = `${Session.get('token')}`;
		}
		return config;
	},
	(error) => {
		// 对请求错误做些什么
		return Promise.reject(error);
	}
);

// 添加响应拦截器
service.interceptors.response.use(
	(response) => {
		// 对响应数据做点什么
		const res = response.data;
		if (res.code && res.code !== 0) {
			// `token` 过期或者账号已在别处登录
			if (res.code === 401 || res.code === 4001) {
				Session.clear(); // 清除浏览器全部临时缓存
				window.location.href = '/'; // 去登录页
				ElMessageBox.alert('你已被登出,请重新登录', '提示', {})
					.then(() => {})
					.catch(() => {});
			}
			return Promise.reject(service.interceptors.response);
		} else {
			return res;
		}
	},
	(error) => {
		// 对响应错误做点什么
		if (error.message.indexOf('timeout') != -1) {
			ElMessage.error('网络超时');
		} else if (error.message == 'Network Error') {
			ElMessage.error('网络连接错误');
		} else {
			if (error.response.data) ElMessage.error(error.response.statusText);
			else ElMessage.error('接口路径找不到');
		}
		return Promise.reject(error);
	}
);

// 导出 axios 实例
export default service;

使用:


import request from '/@/utils/request';

/**
 * (不建议写成 request.post(xxx),因为这样 post 时,无法 params 与 data 同时传参)
 *
 * 登录api接口集合
 * @method signIn 用户登录
 * @method signOut 用户退出登录
 */
export function useLoginApi() {
	return {
		signIn: (data: object) => {
			return request({
				url: '/user/signIn',
				method: 'post',
				data,
			});
		},
		signOut: (data: object) => {
			return request({
				url: '/user/signOut',
				method: 'post',
				data,
			});
		},
	};
}