基于axios 的二次封装

0. axios为什么需要二次封装及好处是什么

通常我们的项目会越做越大,页面也会越来越多,如果页面非常的少,直接用axios也没有什么大的影响,那页面组件多了起来,上百个接口呢,这个时候后端改了接口,有一个请求多加了一个参数什么的呢?那就只有找到发请求那个页面,进去修改,如果多个页面都使用了这个页面发请求,整个过程很繁琐不易于项目的维护和迭代

这个时候如果我们统一的区管理接口,需要修改某一个接口的时候直接在api里修改对应的请求是不是很方便呢?

api统一管理,不管接口有多少,所有的接口都可以非常清晰,容易维护.

通常来说在项目开发中有三个阶段:
1、开发环境
2、测试环境
3、生产环境

不同环境访问接口的域名是不同的,直接修改域名,这就是封装请求的原因。

1.封装目的

此次进行简单的封装,所以暂时没有考虑取消重复请求、重复发送请求、请求缓存等情况!这里主要实现以下目的:

  1. 实现请求拦截
  2. 实现响应拦截
  3. 常见错误信息处理
  4. 请求头设置
  5. api 集中式管理

2.初始化 axios 实例 

请求拦截器

        发送请求之前运行一般会判断是否有token,如果token存在则在请求头加上这个token。服务端会判断我这个token是否过期。可以设置加载全局loading。等

响应拦截器

        对服务端返回的数据进行处理,存储token,错误处理、登录、登录失效路由跳转、关闭全局loading等。

目录结构如下:

 index.js代码如下

/*
 * @Description:
 * @Version: 2.0
 * @Autor: Cookie
 * @Date: 2022-06-28 11:33:32
 * @LastEditors: Zhang
 * @LastEditTime: 2022-06-28 15:38:21
 */
import serverConfig from "./config";
import axios from 'axios'
import qs from "qs";
import { Message, Loading, MessageBox } from 'element-ui';

// loading函数
// 记录请求次数
let needLoadingRequestCount = 0;
let loading;
function startLoading() {
  loading = Loading.service({
    lock: true,
    text: '加载中……',
    background: 'rgba(0, 0, 0, 0.5)',
  });
}
function endLoading() {
  // 延迟500ms,防止网速特快加载中画面一闪而过
  setTimeout(function () {
    if (loading) loading.close();
  }, 500);
}
// 打开loading
function showFullScreenLoading() {
  if (needLoadingRequestCount === 0) {
    startLoading();
  }
  needLoadingRequestCount++;
}
// 关闭loading
function tryHideFullScreenLoading() {
  if (needLoadingRequestCount <= 0) return;
  needLoadingRequestCount--;
  if (needLoadingRequestCount === 0) {
    endLoading();
  }
}

// 创建实例
const serviceAxios = axios.create({
  baseURL: serverConfig.baseURL, // 基础请求地址
  timeout: 10000, // 请求超时设置
  // withCredentials: false, // 跨域请求是否需要携带 cookie
});

// 添加请求拦截器
serviceAxios.interceptors.request.use(
  config => {
    // 在发送请求之前做些什么
    // 打开loading
    showFullScreenLoading();
    // 如果开启 token 认证
    if (serverConfig.useTokenAuthorization) {
      config.headers["Authorization"] = JSON.parse(localStorage.getItem("token")); // 请求头携带 token
    }
    // axios.defaults.headers.common['Authorization'] = localStorage.getItem("token")
    // 设置请求头
    if (!config.headers["content-type"]) { // 如果没有设置请求头
      if (config.method === 'post') {
        config.headers["content-type"] = "application/x-www-form-urlencoded"; // post 请求
        config.data = qs.stringify(config.data); // 序列化,比如表单数据
      } else {
        config.headers["content-type"] = "application/json"; // 默认类型(get)
        // axios.defaults.headers.post['Content-Type'] = 'application/json';

      }
    }
    console.log("请求配置", config);
    return config;
  },
  error => {
    // 对请求错误做些什么
    // 关闭loading
    tryHideFullScreenLoading();
    return Promise.reject(error);
  }
);

// 添加响应拦截器
serviceAxios.interceptors.response.use(
  res => {
    console.log('响应', res)
    // 关闭loading
    tryHideFullScreenLoading();
    let data = res.data
    if (!res.success) {
      // B002:Token 过期了;
      if (res.code === 'B002') {
        // 最后一次出弹框
        if (needLoadingRequestCount === 0) {
          MessageBox.confirm(
            `你已被登出,可以取消继续留在该页面,
            或者重新登录, 确定登出`,
            {
              confirmButtonText: '重新登录',
              cancelButtonText: '取消',
              type: 'warning',
            },
          ).then(() => {
            // 返回登录页
            // ...做些事情
            // 为了重新实例化vue-router对象 避免bug
            location.reload();
          });
        }
      } else {
        Message({
          message: res.msg,
          type: 'error',
        });
      }
    }
    // 对响应数据做点什么
    return data;
  },
  error => {
    console.log('响应fail', error)
    // 对响应错误做点什么
    let message = "";
    if (error && error.response) {
      switch (error.response.status) {
        case 302:
          message = "接口重定向了!";
          break;
        case 400:
          message = "参数不正确!";
          break;
        case 401:
          message = "您未登录,或者登录已经超时,请先登录!";
          break;
        case 403:
          message = "您没有权限操作!";
          break;
        case 404:
          message = `请求地址出错: ${error.response.config.url}`;
          break;
        case 408:
          message = "请求超时!";
          break;
        case 409:
          message = "系统已存在相同数据!";
          break;
        case 500:
          message = "服务器内部错误!";
          break;
        case 501:
          message = "服务未实现!";
          break;
        case 502:
          message = "网关错误!";
          break;
        case 503:
          message = "服务不可用!";
          break;
        case 504:
          message = "服务暂时无法访问,请稍后再试!";
          break;
        case 505:
          message = "HTTP 版本不受支持!";
          break;
        default:
          message = "异常问题,请联系管理员!";
          break;
      }
    }
    return Promise.reject(message);
  }
);
console.log(serviceAxios)

export default serviceAxios; //导出实例

config/index.js代码如下:

const serverConfig = {
  baseURL: 'url',  // 请求基础地址,可根据环境自定义
  useTokenAuthorization: true, // 是否开启 token 认证
}

export default serverConfig

api/user.js

import serviceAxios from "../index";


const login = (data) => {
  return serviceAxios({
    url: "/app/login",
    method: "post",
    data,
  });
}

const getUserInfo = (params) => {
  return serviceAxios({
    url: "/app/getSystemName",
    method: "get",
    params,
  });
}

export {
  login,
  getUserInfo
}

vue文件中使用:

mounted() {
    this.init();
    this.getInfo();
  },
  methods: {
    async init() {
      let params = {
        nickName: "admin",
        password: "6SJ2Lmmt0BKKiSWhQipe+Q=="
      };
      let res = await login(params);
      localStorage.setItem("token", JSON.stringify(res.data)); // 存放token
      console.log(res.data);
    },
    getInfo() {
      let params = {};
      getUserInfo(params).then(res => { // 也可以then的方式链式调用
        console.log(res);
      })
    }
  }

3.总结

我们在此基础上可以根据业务场景做一些以下扩展建议:

  • 请求拦截里面针对 token 进行处理
  • 响应拦截里面判断 token 是否过期等等
  • 在 config/index.js 里面动态更改 baseURL
  • 在请求拦截里面根据业务场景修改请求头
  • 在拦截里面设置全局请求进度条等等

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值