VUE3(十六)封装axios

简介: axios 基础:从浏览器中创建XMLHttpRequest、从node.js发出http请求、支持Promise API、拦截请求和响应、转换请求和响应数据、取消请求、自动转换JSON数据、客户端支持防止CSRF/XSRF。

QQ图片20220423174223.jpg


一:axios 基础


从浏览器中创建XMLHttpRequest


从node.js发出http请求


支持Promise API


拦截请求和响应


转换请求和响应数据


取消请求


自动转换JSON数据


客户端支持防止CSRF/XSRF



二:axios封装


关于Axios的封装这部分涉及到与后端的一些约定。


什么约定呢?就是在我们请求接口的时候,后端会返回给我们一个code。


在我开发的时候,一般约定


code:-200为登录失效状态
code:-100为接口发生错误状态。(为了避免服务器端接口报错导致前端无法运行的情况发生,我的习惯通常是在后端的接口加上try{}catch(){} 来避免接口报错)
code > 0 接口返回成功值
code < 0 接口返回失败值


这样,我们就可以在封装axios的时候提前通过请求返回值code做一些预处理。


1:引入axios


import axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';


2:设置请求超时


通过axios.defaults.timeout设置默认的请求超时时间。例如超过了10s,就会告知用户当前请求超时,请刷新等。


// 超时时间(ms)
axios.defaults.timeout = 2000 * 1000;


3:post请求头的设置


post请求的时候,我们需要加上一个请求头,所以可以在这里进行一个默认的设置,即设置post的请求头为application/x-www-form-urlencoded;charset=UTF-8


// axios 请求头
axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest'
axios.defaults.headers['token'] = localStorage.getItem('token') || ''
axios.defaults.headers.post['Content-Type'] = 'application/json'


4:请求拦截


我们在发送请求前可以进行一个请求的拦截,为什么要拦截呢,

我们拦截请求是用来做什么的呢?


比如,有些请求是需要用户登录之后才能访问的,或者post请求的时候,我们需要序列化我们提交的数据。这时候,我们可以在请求被发送之前进行一个拦截,从而进行我们想要的操作。


// 请求拦截
axios.interceptors.request.use(
  (config: AxiosRequestConfig) => { 
    // 可在这里做一些数据的校验。
    // session的校验等。
    return config 
  },
  (error: AxiosError) => { 
    return error 
  }
)


5:响应拦截


响应拦截器很好理解,就是我在最开始的时候说的那部分和后端的约定,约定好几个固定的状态码,按需执行对应的操作就好。

当然,服务器返回给我们的数据,我们在拿到之前可以对他进行一些处理。


例如上面的思想:如果后台返回的状态码是200,则正常返回数据,否则的根据错误的状态码类型进行一些我们需要的错误。


其实这里主要就是进行了错误的统一处理和没登录或登录过期后调整登录页的一个操作。


// 响应拦截
axios.interceptors.response.use((result: AxiosResponse) => {
  // ===========================================================
  // 返回方式一
  /*console.log(result);
  if (result.status === 200) {
    if (result.data && result.data.code > 0) {
      return Promise.resolve(result);
    } else {
      alert(result.data.msg || "操作失败");
      return Promise.reject(result);
    }
  } else {
    alert("网络异常");
    return Promise.reject(result);
  }//*/
  // ==========================================================
  // 返回方式二
  // 返回数据前做了什么
  // console.log(result);
  if (result.data.code < -100) 
  {
    if (result.data.msg)
    {
      // 调用自定义alert
      utils.alert(result.data.msg, function () {
        window.location.assign('/pc/index');
      });
    }
    return Promise.reject(result.data.data)
  }
  return result;
}, (err: AxiosError) => {
  utils.alertLoadExec(false);
  // 返回数据前做了什么
  return Promise.reject(err)
})


6:封装get,put,post请求


Request.ts


import axios from "axios";
import qs from "qs";
/**
 * 封装请求方式
 */
const request =
{
    /**
     * @name: 封装axios get方法
     * @desc: 描述
     * @author: camellia
     * @email: guanchao_gc@qq.com
     * @date: 2020-12-21 
     * @param url 请求连接
     * @param params 请求参数
     * @param callback 回调方法
     */
    get(url: string, params: any, callback: any) 
    {
        return new Promise((resolve, reject) => {
            axios
                .get(url, {
                    params: params
                })
                .then(res => {
                    callback ? resolve(callback(res.data)) : resolve(res.data);
                })
                .catch(err => {
                    reject(err);
                });
        });
    },
    /**
     * @name: 封装axios post方法
     * @desc: 描述
     * @author: camellia
     * @email: guanchao_gc@qq.com
     * @date: 2020-12-21 
     * @param url 请求连接
     * @param params 请求参数
     * @param callback 回调方法
     */
    post(url: string, params: any, callback: any) 
    {
        return new Promise((resolve, reject) => {
            axios
                .post(url, qs.stringify(params))
                .then(res => {
                    callback ? resolve(callback(res.data)) : resolve(res.data);
                })
                .catch(err => {
                    reject(err);
                });
        });
    },
    /**
     * @name: put请求封装
     * @author: camellia
     * @email: guanchao_gc@qq.com
     * @date: 2021-03-01 
     * @param url 请求连接
     * @param params 请求参数
     * @param callback 回调方法
     */
    put(url: string, params: any, callback: any) 
    {
        return new Promise((resolve, reject) => {
            axios
                .put(url, params)
                .then(res => {
                    callback ? resolve(callback(res.data)) : resolve(res.data);
                }, err => {
                    reject(err)
                })
        })
    },
    /**
     * @name: 请求失败后的错误统一处理
     * @author: camellia
     * @email: guanchao_gc@qq.com
     * @date: 2021-03-08 
     * @param {Number} status 请求失败的状态码
     */
    errorHandle(status:any, other:any)
    {
        // 状态码判断
        switch (status) {
            // 401: 未登录状态,跳转登录页
            case 401:
                // toLogin();
                break;
            // 403 token过期
            // 清除token并跳转登录页
            case 403:
                // tip('登录过期,请重新登录');
                // localStorage.removeItem('token');
                // store.commit('loginSuccess', null);
                setTimeout(() => {
                    // toLogin();
                }, 1000);
                break;
            // 404请求不存在
            case 404:
                // tip('请求的资源不存在');
                break;
            default:
                console.log(other);
        }
    }
}
export default request;


7:axios封装完整代码


import axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
// 公共状态文件
import { common } from "/@/hooks/common.ts";
// 引入公共函数js文件
import utils from "/@/assets/js/public/function";
// 默认请求连接
// axios.defaults.baseURL = "http://xxxx.xxx.xxxx/index.php";
// 超时时间(ms)
axios.defaults.timeout = 2000 * 1000;
// axios请求开启cookie,支持跨域请求携带cookie
axios.defaults.withCredentials = true;
// axios 请求头
axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest'
axios.defaults.headers['token'] = localStorage.getItem('token') || ''
axios.defaults.headers.post['Content-Type'] = 'application/json'
// 请求拦截
axios.interceptors.request.use(
  (config: AxiosRequestConfig) => { 
    // 可在这里做一些数据的校验。
    // session的校验等。
    return config 
  },
  (error: AxiosError) => { 
    return error 
  }
)
// 响应拦截
axios.interceptors.response.use((result: AxiosResponse) => {
  // ===========================================================
  // 返回方式一
  /*console.log(result);
  if (result.status === 200) {
    if (result.data && result.data.code > 0) {
      return Promise.resolve(result);
    } else {
      alert(result.data.msg || "操作失败");
      return Promise.reject(result);
    }
  } else {
    alert("网络异常");
    return Promise.reject(result);
  }//*/
  // ==========================================================
  // 返回方式二
  // 返回数据前做了什么
  // console.log(result);
  if (result.data.code < -100) 
  {
    if (result.data.msg)
    {
      // 调用自定义alert
      utils.alert(result.data.msg, function () {
        window.location.assign('/pc/index');
      });
    }
    return Promise.reject(result.data.data)
  }
  return result;
}, (err: AxiosError) => {
  utils.alertLoadExec(false);
  // 返回数据前做了什么
  return Promise.reject(err)
})
export default axios


8:api统一管理


统一的api管理,我是将每个单页的请求放到一个对应的文件中,这样使用以及管理更加灵活。而且也不会出现多人协作开发的时候,出现重名的情况。

我这里用一个来做例子:


Api文件:articleList.ts


// 引入公共js文件
import request from "/@/hooks/request";
/**
 * @name:根据分类获取文章列表
 * @author: camellia
 * @email: guanchao_gc@qq.com
 * @date: 2021-03-01 
 */
export const getArticleListByCategory = (data: any) => request.get("/index.php/article/getArticleListByCategory", data, '');


页面文件:articleList.ts


import {
    PropType,
    ref,
    watch,
    reactive,
    toRefs,
    provide,
    inject,
} from "vue";
// 引入axios钩子
import axios from "/@/hooks/axios.ts";
// 引入路由
import { useRouter, useRoute } from "vue-router";
import HelloWorld from "/@/components/HelloWorld.vue";
import Footer from "/@/components/pc/Footer.vue";
import Header from "/@/components/pc/Header.vue";
import Menu from "/@/components/pc/Menu.vue";
import load from "/@/components/pc/loading.vue";
import TopIM from "/@/components/pc/TopIM.vue";
import Drawer from "/@/components/pc/Drawer.vue";
import Pagination from "/@/components/pc/Pagination.vue";
// 引入公共js文件
import utils from "/@/assets/js/public/function";
// api 接口文件
import { getArticleListByCategory } from "/@/api/pc/articleList.ts";
// 公共状态文件
import { common } from "/@/hooks/common.ts";
export default {
    name: "articleList",
    components: {
        HelloWorld,
        Footer,
        Header,
        Menu,
        load,
        TopIM,
        Drawer,
        Pagination
    },
    // VUE3 语法 第一个执行的钩子函数
    // setup官方文档
    // https://www.vue3js.cn/docs/zh/guide/composition-api-setup.html#参数
    setup(props: any, content: any) {
        // 实例化路由
        const router = useRouter();
        const route = useRoute();
        /**
         * @name: 声明data
         * @author: camellia
         * @email: guanchao_gc@qq.com
         * @date: 2021-01-18 
         */
        const data = reactive({
            showRef: 0,
            // loading 是否显示
            loading: true,
            // 文章列表
            articleList: [],
            // 数据页数
            articlePage: 0,
            // 当前页
            currentPage: route.query.page ? route.query.page : 1,
            // 分页显示页码数
            dataNum: 7,
            // 分类id
            cate_id: route.query.cate_id ? route.query.cate_id : '',
            // 分类名称
            cat_name:'',
            // 分类列表
            categoryList:'',
            // 子分类
            cate_id_son: route.query.cate_id_son ? route.query.cate_id_son : '',
            // 标签id
            label_id: route.query.label_id ? route.query.label_id : '',
            // 搜索字符串
            search: route.query.search ? route.query.search : '',
        });
        /**
         * @name: 监听搜索值变化
         * @author: camellia
         * @email: guanchao_gc@qq.com
         * @date: 2020-12-21 
         */
        watch(
            () => common.search,
            () => {
                data.search = common.search;
                data.currentPage = 1;
                data.cate_id = '';
                data.cate_id_son = '';
                data.label_id = '';
                getData();
            }
        );
        /**
         * @name: loading显示时间
         * @author: camellia
         * @email: guanchao_gc@qq.com
         * @date: 2020-12-21 
         */
        // utils.sleep(1000).then(() => {
        //     // 这里写sleep之后需要去做的事情
        //     data.loading = false;
        //     common.loading = data.loading;
        // });
        // ===================================================================
        /**
         * @name: 右上角菜单
         * @author: camellia
         * @email: guanchao_gc@qq.com
         * @date: 2021-01-15 
         * @param:  param   number  menu是否显示
         * @param:  cate    number  显示文章分类id
         */
        const closeMenu = (param: number,cate:string='') => {
            // param就是子组件传过来的值
            data.showRef = param;
            if(cate != '')
            {
                data.cate_id = cate;
                data.currentPage = 1;
                data.cate_id_son = '';
                data.label_id = '';
                getData();
            }
        }
        const showMenuByChild = (param: number) => {
            data.showRef = param;
            // this.$refs.menuShowObj.getSrcList(this.showRef);
        }
        // ===================================================================
        /**
         * @name: 获取初始数据
         * @author: camellia
         * @email: guanchao_gc@qq.com
         * @date: 2021-01-15 
         */
        const getData = () => {
            // 文档 :http://www.axios-js.com/zh-cn/docs/
            let info = {
                page: data.currentPage,
                cate_id: data.cate_id,
                cate_id_son: data.cate_id_son,
                search:data.search,
                label_id:data.label_id
            };
            let param = utils.createRouterParam(info);
            data.loading = true;
            try {
                getArticleListByCategory(param).then(function (response: any) {
                    data.cat_name = response.cateName;
                    data.categoryList = response.cateList;
                    data.articlePage = response.articlePage;
                    data.articleList = response.articleShow;
                    data.loading = false;
                    utils.goToScrollTop();
                });
            } catch (error) {
                utils.alertMsg(2000, '系统错误');
            }
            /*axios.get('/index.php/article/getArticleListByCategory', { params: param })
                .then(function (response: any) {
                    data.cat_name = response.data.cateName;
                    data.categoryList = response.data.cateList;
                    data.articlePage = response.data.articlePage;
                    data.articleList = response.data.articleShow;
                    data.loading = false;
                    utils.goToScrollTop();
                })
                .catch(function (error: any) { });//*/
        }
        // =============================================================================
        // 初始调用
        getData();
        /**
         * @name: 将data绑定值dataRef
         * @author: camellia
         * @email: guanchao_gc@qq.com
         * @date: 2021-01-10 
         */
        const dataRef = toRefs(data);
        return {
            showMenuByChild,
            // showMenu ,
            closeMenu,
            ...dataRef
        }
    }
};


以上大概就是对axios封装的一些我的理解。



目录
相关文章
|
2月前
|
资源调度 JavaScript 前端开发
vue-element-admin 综合开发四:axios安装和封装、mock安装/学习/使用
这篇文章是关于如何在Vue项目中使用axios进行网络请求、二次封装axios以及使用mockjs模拟响应数据的教程。
96 1
vue-element-admin 综合开发四:axios安装和封装、mock安装/学习/使用
|
2月前
|
资源调度 JavaScript
|
2月前
|
缓存 JavaScript 搜索推荐
|
2月前
|
前端开发 JavaScript 安全
在vue前端开发中基于refreshToken和axios拦截器实现token的无感刷新
在vue前端开发中基于refreshToken和axios拦截器实现token的无感刷新
149 4
|
2月前
vue3 + Ts 中 使用 class 封装 axios
【10月更文挑战第8天】
153 1
|
2月前
vue3 + Ts 中 使用 class 封装 axios
【10月更文挑战第5天】
185 1
|
2月前
|
前端开发 JavaScript API
自己动手封装axios通用方法并上传至私有npm仓库:详细步骤与实现指南
自己动手封装axios通用方法并上传至私有npm仓库:详细步骤与实现指南
117 0
|
JavaScript 前端开发 Java
带你玩转vue——高效封装axios
带你玩转vue——高效封装axios
|
25天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的