axios

1. axios

  1. 什么是axios?
    axios是 前端最流行的 ajax 请求库
    react/vue 官方都推荐使用 axios 发 ajax 请求
  2. axios特点?
    (1)基于 xhr + promise 的异步 ajax 请求库
    (2)浏览器端/node 端都可以使用
    (3)支持请求/响应拦截器
    (4)支持请求取消
    (5)请求/响应数据转换
    (6)批量发送多个请求

1. 1 axios基本使用

  • 发送GET请求
//获取按钮 GET请求
        const btns = document.querySelectorAll('button')
        // 第一个
        btns[0].oncilck = function () {
            // 发送AJAX请求
            axios({
                // 请求类型
                method: 'GET',
                // URL
                url: 'http://localhost:3000/posts/2',
            }).then(response => {
                console.log(response
                );
            })
        }
  • 发送POST请求
//添加一篇新的文章 POST请求
        btns[1].oncilck = function () {
            // 发送AJAX请求
            axios({
                // 请求类型
                method: 'POST',
                // URL
                url: 'http://localhost:3000/posts',
                // 设置请求体
                data: {
                    title: '今天天气不错',
                    author: '张三'
                }
            }).then(response => {
                console.log(response);
            })
        }
  • 发送PUT请求
// PUT请求
        btns[2].oncilck = function () {
            // 发送AJAX请求
            axios({
                // 请求类型
                method: 'PUT',
                // URL
                url: 'http://localhost:3000/posts/3',
                // 设置请求体
                data: {
                    title: '今天天气不错',
                    author: '李四'
                }
            }).then(response => {
                console.log(response);
            })
        }
  • 发送DELETE请求
// 删除数据
        btns[3].oncilck = function () {
            // 发送AJAX请求
            axios({
                // 请求类型
                method: 'PUT',
                // URL
                url: 'http://localhost:3000/posts/3',
            }).then(response => {
                console.log(response);
            })
        }

1.2 axios其他请求方式

  • 发送GET请求
// 发送 GET 请求
        btns[0].onclick = function(){
            axios.request({
                method: 'GET',
                url: 'http://localhost:3000/comments'
            }).then(response => {
                console.log(response);
            })
        }
  • 发送POST请求
btns[1].onclick = function(){
            axios.post('http://localhost:3000/comments', 
            {
                "body": '喜大普奔',
                "postId": 2
            }).then(response => {
                console.log(response);
            })
        }

1.3 axios默认配置

 const btns = document.querySelectorAll('button')
        // 默认配置
        axios.defaults.method = 'GET'; //设置默认的请求类型为GET
        axios.defaults.baseURL = 'http://localhost:3000';//设置基础URL
        axios.defaults.params = {id: 100};
        axios.defaults.timeout = 3000;
        btns[0].oncilck = function () {
            // 发送AJAX请求
            axios({
                // URL
                url: '/posts/2',
            }).then(response => {
                console.log(response
                );
            })
        }

1.4 axios创建实例对象

const btns = document.querySelectorAll('button')

        // 创建实例对象
        const duanzi = axios.create({
            baseURL: 'https://api.apiopen.top',
            timeout:2000
        });
        // 这里 duanzi 与 axios 对象的功能几近是一样的
        // duanzi({
        //     url: '/getJoke',
        // }).then(response => {
        //     console.log(response);
        // })

        duanzi.get('/getJoke').then(response => {
            console.log(response.data);
        })

1.5 axios拦截器

 // Promise
        // 设置请求拦截器
        axios.interceptors.request.use(function(config){
            console.log('请求拦截器成功');
            return config;
        }, function(error) {
            console.log('请求拦截器失败');
            return Promise.reject(error)
        });

        // 设置响应拦截器
        axios.interceptors.response.use(function(response){
            console.log('响应拦截器成功');
            return response;
        }, function(error){
            console.log('响应拦截器失败');
            return Promise.reject(error)
        })

        // 发送请求
        axios ({
            method: 'GET',
            url: 'http://localhost:3000/posts'
        }).then(response => {
            console.log('自定义回调处理成功的结果');
            // console.log(response);
        })

1.6 axios取消请求

const btns = document.querySelectorAll('button')
        // 声明全局变量
        let cancel = null;
        btns[0].onclick = function(){
            // 检测上一次请求是否已经完成
            if(cancel != null){
                // 取消上一次请求
                cancel()
            }
            // 发送AJAX请求
            axios({
                method: 'GET',
                url: 'http://localhost:3000/posts',
                // 添加配置对象的属性
                cancelToken: new axios.cancelToken(function(c){
                    // 将c的值赋值给cancel
                    cansel = c;
                })
            }).then(response => {
                console.log(response);
                // 将cancel的值初始化
                cancel = null
            })
        }

        // 绑定第二个时间取消请求
        btns[1].onclick = function(){
            cancel()
        }

1.7 axios源码分析

#为注释
├── /dist/ # 项目输出目录
├── /lib/ # 项目源码目录
│ ├── /adapters/ # 定义请求的适配器 xhr、http
│ │ ├── http.js # 实现 http 适配器(包装 http 包)
│ │ └── xhr.js # 实现 xhr 适配器(包装 xhr 对象)
│ ├── /cancel/ # 定义取消功能
│ ├── /core/ # 一些核心功能
│ │ ├── Axios.js # axios 的核心主类
│ │ ├── dispatchRequest.js # 用来调用 http 请求适配器方法发送请求的函数
│ │ ├── InterceptorManager.js # 拦截器的管理器
│ │ └── settle.js # 根据 http 响应状态,改变 Promise 的状态
│ ├── /helpers/ # 一些辅助方法
│ ├── axios.js # 对外暴露接口
│ ├── defaults.js # axios 的默认配置
│ └── utils.js # 公用工具
├── package.json # 项目信息
├── index.d.ts # 配置 TypeScript 的声明文件
└── index.js # 入口文件

  • axios发送请求
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title> axios 的由来</title>
    <!-- <script src="./node_modules/axios/dist/mine-axios.js"></script> -->
</head>
<body>
    <script>
        // console.log(axios);
        // axios();
        // axios.get();
        // axios.post();

        //构造函数
        function Axios(config){
            //初始化
            this.defaults = config;//为了创建 default 默认属性
            this.intercepters = {
                request: {},
                response: {}
            }
        }
        //原型添加相关的方法
        Axios.prototype.request = function(config){
            console.log('发送 AJAX 请求 请求的类型为 '+ config.method);
        }
        Axios.prototype.get = function(config){
            return this.request({method: 'GET'});
        }
        Axios.prototype.post = function(config){
            return this.request({method: 'POST'});
        }

        //声明函数
        function createInstance(config){
            //实例化一个对象
            let context = new Axios(config);// context.get()  context.post()  但是不能当做函数使用 context() X
            //创建请求函数
            let instance = Axios.prototype.request.bind(context);// instance 是一个函数 并且可以 instance({})  此时 instance 不能 instance.get X
            //将 Axios.prototype 对象中的方法添加到instance函数对象中
            Object.keys(Axios.prototype).forEach(key => {
                instance[key] = Axios.prototype[key].bind(context);// this.default  this.interceptors
            });
            //为 instance 函数对象添加属性 default 与 interceptors
            Object.keys(context).forEach(key => {
                instance[key] = context[key];
            });
            return instance;
        }

        let axios = createInstance();
        //发送请求
        // axios({method:'POST'});
        axios.get({});
        axios.post({});




    </script>
</body>
</html>
  • axios请求发送
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>请求发送过程</title>
    <!-- <script src="./node_modules/axios/dist/mine-axios.js"></script> -->
</head>
<body>
    <script>
        // axios 发送请求   axios  Axios.prototype.request  bind
        //1. 声明构造函数
        function Axios(config){
            this.config = config;
        }
        Axios.prototype.request = function(config){
            //发送请求
            //创建一个 promise 对象
            let promise = Promise.resolve(config);
            //声明一个数组
            let chains = [dispatchRequest, undefined];// undefined 占位
            //调用 then 方法指定回调
            let result = promise.then(chains[0], chains[1]);
            //返回 promise 的结果
            return result;
        }

        //2. dispatchRequest 函数
        function dispatchRequest(config){
            //调用适配器发送请求
            return xhrAdapter(config).then(response => {
                //响应的结果进行转换处理
                //....
                return response;
            }, error => {
                throw error;
            });
        }

        //3. adapter 适配器
        function xhrAdapter(config){
            console.log('xhrAdapter 函数执行');
            return new Promise((resolve, reject) => {
                //发送 AJAX 请求
                let xhr = new XMLHttpRequest();
                //初始化
                xhr.open(config.method, config.url);
                //发送
                xhr.send();
                //绑定事件
                xhr.onreadystatechange = function(){
                    if(xhr.readyState === 4){
                        //判断成功的条件
                        if(xhr.status >= 200 && xhr.status < 300){
                            //成功的状态
                            resolve({
                                //配置对象
                                config: config,
                                //响应体
                                data: xhr.response,
                                //响应头
                                headers: xhr.getAllResponseHeaders(), //字符串  parseHeaders
                                // xhr 请求对象
                                request: xhr,
                                //响应状态码
                                status: xhr.status,
                                //响应状态字符串
                                statusText: xhr.statusText
                            });
                        }else{
                            //失败的状态
                            reject(new Error('请求失败 失败的状态码为' + xhr.status));
                        }
                    }
                }
            });
        }


        //4. 创建 axios 函数
        let axios = Axios.prototype.request.bind(null);
        axios({
            method:'GET',
            url:'http://localhost:3000/posts'
        }).then(response => {
            console.log(response);
        });
    </script>
</body>
</html>
  • axios拦截器
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>拦截器</title>
    <script src="./node_modules/axios/dist/mine-axios.js"></script>
</head>
<body>
    <script>
        console.dir(axios);
        // 设置请求拦截器  config 配置对象
        axios.interceptors.request.use(function one(config) {
            console.log('请求拦截器 成功 - 1号');
            return config;
        }, function one(error) {
            console.log('请求拦截器 失败 - 1号');
            return Promise.reject(error);
        });

        axios.interceptors.request.use(function two(config) {
            console.log('请求拦截器 成功 - 2号');
            return config;
        }, function two(error) {
            console.log('请求拦截器 失败 - 2号');
            return Promise.reject(error);
        });

        // 设置响应拦截器
        axios.interceptors.response.use(function (response) {
            console.log('响应拦截器 成功 1号');
            return response;
        }, function (error) {
            console.log('响应拦截器 失败 1号')
            return Promise.reject(error);
        });

        axios.interceptors.response.use(function (response) {
            console.log('响应拦截器 成功 2号')
            return response;
        }, function (error) {
            console.log('响应拦截器 失败 2号')
            return Promise.reject(error);
        });

        //发送请求
        axios({
            method: 'GET',
            url: 'http://localhost:3000/posts'
        }).then(response => {
            console.log(response);
        });
    </script>
</body>
</html>
  • axios拦截器模拟实现
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>拦截器</title>
    <!-- <script src="./node_modules/axios/dist/mine-axios.js"></script> -->
</head>
<body>
    <script>
        //构造函数
        function Axios(config){
            this.config = config;
            this.interceptors = {
                request: new InterceptorManager(),
                response: new InterceptorManager(),
            }
        }
        //发送请求  难点与重点
        Axios.prototype.request = function(config){
            //创建一个 promise 对象
            let promise = Promise.resolve(config);
            //创建一个数组
            const chains = [dispatchRequest, undefined];
            //处理拦截器
            //请求拦截器 将请求拦截器的回调 压入到 chains 的前面  request.handles = []
            this.interceptors.request.handlers.forEach(item => {
                chains.unshift(item.fulfilled, item.rejected);
            });
            //响应拦截器
            this.interceptors.response.handlers.forEach(item => {
                chains.push(item.fulfilled, item.rejected);
            });

            // console.log(chains);
            //遍历
            while(chains.length > 0){
                promise = promise.then(chains.shift(), chains.shift());
            }

            return promise;
        }

        //发送请求
        function dispatchRequest(config){
            //返回一个promise 队形
            return new Promise((resolve, reject) => {
                resolve({
                    status: 200,
                    statusText: 'OK'
                });
            });
        }
       
        //创建实例
        let context = new Axios({});
        //创建axios函数
        let axios = Axios.prototype.request.bind(context);
        //将 context 属性 config interceptors 添加至 axios 函数对象身上
        Object.keys(context).forEach(key => {
            axios[key] = context[key];
        });

        //拦截器管理器构造函数
        function InterceptorManager(){
            this.handlers = [];
        }
        InterceptorManager.prototype.use = function(fulfilled, rejected){
            this.handlers.push({
                fulfilled,
                rejected
            })
        }


        //以下为功能测试代码
        // 设置请求拦截器  config 配置对象
        axios.interceptors.request.use(function one(config) {
            console.log('请求拦截器 成功 - 1号');
            return config;
        }, function one(error) {
            console.log('请求拦截器 失败 - 1号');
            return Promise.reject(error);
        });

        axios.interceptors.request.use(function two(config) {
            console.log('请求拦截器 成功 - 2号');
            return config;
        }, function two(error) {
            console.log('请求拦截器 失败 - 2号');
            return Promise.reject(error);
        });

        // 设置响应拦截器
        axios.interceptors.response.use(function (response) {
            console.log('响应拦截器 成功 1号');
            return response;
        }, function (error) {
            console.log('响应拦截器 失败 1号')
            return Promise.reject(error);
        });

        axios.interceptors.response.use(function (response) {
            console.log('响应拦截器 成功 2号')
            return response;
        }, function (error) {
            console.log('响应拦截器 失败 2号')
            return Promise.reject(error);
        });


        //发送请求
        axios({
            method: 'GET',
            url: 'http://localhost:3000/posts'
        }).then(response => {
            console.log(response);
        });
    </script>
</body>
</html>
  • axios请求取消
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>取消请求</title>
    <link crossorigin='anonymous' href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <script src="./node_modules/axios/dist/mine-axios.js"></script>
</head>
<body>
    <div class="container">
        <h2 class="page-header">axios取消请求</h2>
        <button class="btn btn-primary"> 发送请求 </button>
        <button class="btn btn-warning"> 取消请求 </button>
    </div>
    <script>
        //获取按钮
        const btns = document.querySelectorAll('button');
        //2.声明全局变量
        let cancel = null;
        //发送请求
        btns[0].onclick = function(){
            //检测上一次的请求是否已经完成
            if(cancel !== null){
                //取消上一次的请求
                cancel();
            }

            //创建 cancelToken 的值
            let cancelToken = new axios.CancelToken(
                function(c){
                    //3. 将 c 的值赋值给 cancel
                    cancel = c;
                });

            axios({
                method: 'GET',
                url: 'http://localhost:3000/posts',
                //1. 添加配置对象的属性
                cancelToken: cancelToken
            }).then(response => {
                console.log(response);
                //将 cancel 的值初始化
                cancel = null;
            })
        }

        //绑定第二个事件取消请求
        btns[1].onclick = function(){
            cancel();
        }
    </script>   
</body>
</html>
  • axios请求取消模拟实现
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>取消请求</title>
    <link crossorigin='anonymous' href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <!-- <script src="./node_modules/axios/dist/mine-axios.js"></script> -->
</head>
<body>
    <div class="container">
        <h2 class="page-header">axios取消请求</h2>
        <button class="btn btn-primary"> 发送请求 </button>
        <button class="btn btn-warning"> 取消请求 </button>
    </div>
    <script>
        //构造函数
        function Axios(config){
            this.config = config;
        }
        //原型 request 方法
        Axios.prototype.request = function(config){
            return dispatchRequest(config);
        }
        //dispatchRequest 函数
        function dispatchRequest(config){
            return xhrAdapter(config);
        }
        //xhrAdapter
        function xhrAdapter(config){
            //发送 AJAX 请求
            return new Promise((resolve, reject) => {
                //实例化对象
                const xhr = new XMLHttpRequest();
                //初始化
                xhr.open(config.method, config.url);
                //发送
                xhr.send();
                //处理结果
                xhr.onreadystatechange = function(){
                    if(xhr.readyState === 4){
                        //判断结果
                        if(xhr.status >= 200 && xhr.status < 300){
                            //设置为成功的状态
                            resolve({
                                status: xhr.status,
                                statusText: xhr.statusText
                            });
                        }else{
                            reject(new Error('请求失败'));
                        }
                    }
                }
                //关于取消请求的处理
                if(config.cancelToken){
                    //对 cancelToken 对象身上的 promise 对象指定成功的回调
                    config.cancelToken.promise.then(value => {
                        xhr.abort();
                        //将整体结果设置为失败
                        reject(new Error('请求已经被取消'))
                    });
                }
            })
        }

        //创建 axios 函数
        const context = new Axios({});
        const axios = Axios.prototype.request.bind(context);

        //CancelToken 构造函数
        function CancelToken(executor){
            //声明一个变量
            var resolvePromise;
            //为实例对象添加属性
            this.promise = new Promise((resolve) => {
                //将 resolve 赋值给 resolvePromise
                resolvePromise = resolve
            });
            //调用 executor 函数
            executor(function(){
                //执行 resolvePromise 函数
                resolvePromise();
            });
        }

        //获取按钮 以上为模拟实现的代码
        const btns = document.querySelectorAll('button');
        //2.声明全局变量
        let cancel = null;
        //发送请求
        btns[0].onclick = function(){
            //检测上一次的请求是否已经完成
            if(cancel !== null){
                //取消上一次的请求
                cancel();
            }

            //创建 cancelToken 的值
            let cancelToken = new CancelToken(function(c){
                cancel = c;
            });

            axios({
                method: 'GET',
                url: 'http://localhost:3000/posts',
                //1. 添加配置对象的属性
                cancelToken: cancelToken
            }).then(response => {
                console.log(response);
                //将 cancel 的值初始化
                cancel = null;
            })
        }

        //绑定第二个事件取消请求
        btns[1].onclick = function(){
            cancel();
        }
    </script>   
</body>
</html>

1.8 axios 与 Axios 的关系 ?

  1. 从语法上来说: axios 不是 Axios 的实例
  2. 从功能上来说: axios 是 Axios 的实例
  3. axios 是 Axios.prototype.request 函数 bind()返回的函数
  4. axios 作为对象有 Axios 原型对象上的所有方法, 有 Axios 对象上所有属性

你可能感兴趣的:(javascript,前端,vue.js)