封装axios统一调用接口

605 阅读3分钟

前言:

当项目中用到了非常多的接口时,我们不可能每次都引入axios,然后使用axios来发送请求;这样用起来不仅代码赘余且不利于后期的维护,

因此我们需要封装axios,把所有的接口统一放在一个模块内(我一般命名为api或者model),在需要调用接口的时候引用这个模块内封装好的接口函数即可。

一般的请求流程大致分为三个步骤(一般方式)

1.请求进入请求拦截器之前

请求调整或者配置用户标识:

instance.interceptors.request.use((reqConfig) => {
    const token = pmsStore.state.token;
    if (token) {
        reqConfig.headers['Authorization'] = 'Bearer ' + token;
    }
​
    return reqConfig;
}, (error) => Promise.reject(error));
2.真正的请求(创建axios实例)
const instance = axios.create({
    baseURL: network.baseDomain + network.basePath,
    timeout: network.timeout,
    withCredentials: false,
    headers: {
        'Content-Type': 'application/json;charset=UTF-8'
    }
});
3.请求从响应拦截器出来后

对相应的错误进行处理

  • 网络错误处理(断网)

  • 授权错误处理(没有权限 401)

  • 超时处理(403)

  • 普通错误处理等等

    instance.interceptors.response.use((response) => {
    ​
        // 请求成功
        if (response.data.success && response.status <= 200) {
            return {
                data: response.data.result,
                errorMessage: null,
                success: true
            };
        }
    ​
        message.error(response?.data?.error?.message ?? "请求出错");
    ​
        return Promise.reject({
            data: null,
            success: false,
            errorMessage: response.data.error.message
        });
    ​
    }, (error) => {
    ​
        const responseData = error.response.data;
    ​
        const res = {
            success: false,
            data: null,
            errorMessage: 'Request error'
        };
    ​
        if (error.response) {
            switch (error.response.status) {
                case 403:
                    // Todo: 处理 token 过期
                    break;
                case 500:
                    const isStr = typeof responseData === 'string';
                    res.errorMessage = isStr ? responseData : responseData.error.message;
                    break;
            }
            message.error(res.errorMessage);
            return Promise.reject(res);
        }
    ​
        // 断网
        if (!window.navigator.onLine) {
            res.errorMessage = '网络已断开';
        }
    ​
        message.error(res.errorMessage ?? '请求出错');
    ​
        return Promise.reject(res);
    });
    ​
    
针对接口所有的请求类型进行处理 (get post pull等等)
class Http {
​
    /**
     * @param {AxiosRequestConfig} config
     * @return {Promise<HttpResponse>}
     */
    static request(config) {
        return instance(config);
    }
​
    /**
     * GET
     *
     * @param {string} url
     * @param {object} query
     * @return {Promise<HttpResponse | HttpResponsePager>}
     */
    static get({ url, query = null }) {
        return instance.get(url, {
            params: query
        });
    }
​
    /**
     * POST
     *
     * @param {string} url
     * @param {object} data
     * @param {object} query
     * @return {Promise<HttpResponse>}
     */
    static post({ url, data = null, query = null }) {
        return instance.post(url, data, {
            params: query
        });
    }
​
    /**
     * PUT
     *
     * @param {string} url
     * @param {object} data
     * @param {object} query
     * @return {Promise<HttpResponse>}
     */
    static put({ url, data = null, query = null }) {
        return instance.put(url, data, {
            params: query
        });
    }
​
}
export default Http;
在统一封装接口的模块(一般是api或者model)引入封装的axios
import Http from "@/utils/Http";
​
export default {
    //查询
    getInfo(params) {
        return Http.get({
            url: '请求路径',
            query: {
               ...params
            },
        });
    },
}
接口使用
 import Api from "@/api/InfoManage/index";
​
 
 search() {
            const data = {
                page: this.pagination.page,
                rows: this.pagination.pageSize,
            }
            Api.getInfo({...data})
                .then((res) => {
                    this.tableData = res.data.items;
                    this.pagination.total = res.data.totalCount;
                })
                .catch((err) => {
                    console.log(err);
                })
        },

其他方式:直接封装一个axios请求

import axios from "axios";
import {message} from 'ant-design-vue'
import {requestRouter} from '@/router'
import {removeToken, updateToken} from './token'
import config from './config';
//配置基准路径和默认超时时间
const hostName = config.baseURL;
axios.defaults.baseURL = hostName;
axios.defaults.timeout = config.timeout;
//封装axios请求
const BizRequest = (
  url,
  method = "get",
  data = {},
  params = {},
  grant_type //该字段存在表示用户已登录,token存在(业务需求)
) => {
​
  let options = {
    url,
    method,
    data,
    params,
    headers: {},
  };
​
  if (grant_type) {
    options = {
      ...options,
      headers: {
        "Content-Type": "application/json"
      },
      data: {...data}
    };
  }
  return new Promise((resolve, reject) => {
  //配置用户标识
    const tokenString = window.localStorage.getItem("ems_access_token");
    if (tokenString) {
      axios.defaults.headers["Authorization"] = "Bearer " + tokenString;
    }
    axios(options)
      .then(async (response) => {
        if (response.status === 200) {
        //更新用户状态
          if (grant_type) {
            updateToken(
              response.data.result.accessToken,
              response.data.result.encryptedAccessToken,
              response.data.result.expireInSeconds
            );
            resolve(response);
          } else {
            if (!response.data.success) {
              message.error(response?.data?.error?.details || response?.data?.error?.message);
              reject(response.data)
            } else {
              resolve(response.data);
            }
          }
        }
      })
      .catch(async (err) => {
      //对错误进行处理
        if (err?.response?.status === 401) {
          message.error("登陆凭证过期,请重新登陆!");
          removeToken();
          requestRouter.replace('/login');
        } else {
          message.error(err?.response?.data?.error?.details || err?.response?.data?.error?.message);
        }
        reject(err?.response);
      });
  });
};
​
export default request;
export {removeToken};
​
在统一封装接口的模块引入封装的axios
import request from '@/utils/request'export default {
  query(params) {
    return request('请求地址', "post", null, params);
  },
  create(data) {
    return request('请求地址', 'post', data);
  },
  update(data) {
    return request('请求地址', 'post', data);
  },
  delete(params) {
    return request('请求地址', 'get', null, params);
  }
};
​
接口使用
 import Api from "@/api/bigEvent";
 
  onDelete(id) {
      Api.delete({ id }).then(() => {
        this.$message.success("删除成功");
        this.search();
      });
    },