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封装的一些我的理解。



目录
相关文章
|
1月前
|
资源调度 JavaScript 前端开发
vue-element-admin 综合开发四:axios安装和封装、mock安装/学习/使用
这篇文章是关于如何在Vue项目中使用axios进行网络请求、二次封装axios以及使用mockjs模拟响应数据的教程。
74 1
vue-element-admin 综合开发四:axios安装和封装、mock安装/学习/使用
|
1月前
|
资源调度 JavaScript
|
1月前
|
缓存 JavaScript 搜索推荐
|
27天前
|
前端开发 JavaScript 安全
在vue前端开发中基于refreshToken和axios拦截器实现token的无感刷新
在vue前端开发中基于refreshToken和axios拦截器实现token的无感刷新
71 4
|
1月前
vue3 + Ts 中 使用 class 封装 axios
【10月更文挑战第8天】
100 1
|
1月前
vue3 + Ts 中 使用 class 封装 axios
【10月更文挑战第5天】
121 1
|
27天前
|
前端开发 JavaScript API
自己动手封装axios通用方法并上传至私有npm仓库:详细步骤与实现指南
自己动手封装axios通用方法并上传至私有npm仓库:详细步骤与实现指南
73 0
|
3月前
|
JavaScript 前端开发
【Vue面试题二十五】、你了解axios的原理吗?有看过它的源码吗?
这篇文章主要讨论了axios的使用、原理以及源码分析。 文章中首先回顾了axios的基本用法,包括发送请求、请求拦截器和响应拦截器的使用,以及如何取消请求。接着,作者实现了一个简易版的axios,包括构造函数、请求方法、拦截器的实现等。最后,文章对axios的源码进行了分析,包括目录结构、核心文件axios.js的内容,以及axios实例化过程中的配置合并、拦截器的使用等。
【Vue面试题二十五】、你了解axios的原理吗?有看过它的源码吗?
|
3月前
|
JavaScript 前端开发
【Vue面试题二十七】、你了解axios的原理吗?有看过它的源码吗?
文章讨论了Vue项目目录结构的设计原则和实践,强调了项目结构清晰的重要性,提出了包括语义一致性、单一入口/出口、就近原则、公共文件的绝对路径引用等原则,并展示了单页面和多页面Vue项目的目录结构示例。

热门文章

最新文章

  • 1
    若依修改,若依如何发送请求---王清江07,axios的请求在request.js文件中,若依发送GET请求,必须用param
    115
  • 2
    axios发送post请求,如何接受和返回一个axios的字段,解决bug的方法,困难的事情先从简单做起,先从发送一个axios的post请求做起,解决方法查别人的资料,查看F12看network就行
    39
  • 3
    文本,前后端数据交互,简单请求,如何去给data数据赋值,在mounted()里赋值,利用axios发送的请求,res就是数据集,就是后端的数据,this.users = res.data.data
    44
  • 4
    Request failed with status code 400,使用axios.post要发送参数,认真比对原项目,看看有没有忘记什么?
    83
  • 5
    vue3 在 watchEffect 里中断未完成的 axios 请求(只保留最后一次请求的方法---连续点击查询按钮的优化)
    112
  • 6
    前后端数据交互.js文件的axios的写法,想要往后端发送数据,页面注入API,await的意思是同步等待服务器数据,并返回,axios注入在其他页面,其他页面调用的时候,同步作用
    42
  • 7
    前后端数据交互,API风格组合式API和选项式API,setup是一个标识,组合式编写的意思,使定义count.value的值自增的写法,组合式API使用axios的写法,ref定义响应数据写法
    27
  • 8
    网页设计,若依项目修改(It must be done)02------axios封装后发get请求,axios请求的位置在呢?
    43
  • 9
    前后端数据交互之axios的路径怎样找?axios的路径是那个,是你打开Tomcat之后,出现的路径+你项目写的接口路径
    33
  • 10
    数据交互,前后端数据请求,axios请求,对象结构的使用,E6的使用,结构赋值是什么?函数形参的obj如何,函数形参的obj就改成对象结构接收传入的数据对象
    24