Axios

Axios

1、了解Axios

(一)了解Axios

一、特点

  1. 在浏览器端能发送ajax请求

  2. 能在node.js中发送http请求

  3. 支持promise的相关操作(API)

  4. 请求和响应的拦截器(能在请求之前做一些准备工作,在响应回来后对响应的结果做一些处理)

  5. 对请求和响应的数据做转换

  6. 取消请求

  7. 自动将结果转换成json格式数据

  8. 保护作用阻止XSRF攻击

 

官方文档:http://axios-js.com/zh-cn/docs/index.html

GIthub:https://github.com/axios/axios

 

如果测试,可以使用这个进行配合使用:npm install -g json-server

官网:https://github.com/typicode/json-server

2、安装

1)使用npm(包管理工具)最后通过打包工具引入(项目使用)

$ npm install axios

2)使用bower(包管理工具)一般在页面使用script标签引入

$ bower install axios

3)使用yarn(包管理工具)(项目使用)

$ yarn add axios

4 ) cdn导入:

 <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.0.0-alpha.1/axios.js"></script>

5)全局注册

全局注册:

01、import http from ‘axios’ // 首先在main.js引入

02、Vue.prototype.$http = http // 注册

03、测试使用,例:this.$http.get(‘/xxx’).then(…)

 

3、基本使用

1、axios发送请求方法

request、get、post、put、head、delete、options、patch等一系列http请求类型方法

2、axios请求响应结构

headers:响应头信息;

data:响应体的结果(服务器响应的结果,进行了json解析);

config:配置对象(包括了请求类型等等);

request:原生的ajax请求对象,也就是xhlhttprequest实例对象;

status:响应状态码,statusText:响应字符串

3、请求对象

可以查看官方文档:https://github.com/axios/axios

4、基本使用:(发送GET、POST、PUT、DELETE请求)

  1. 代码实现

 <div class="container">
       <h1 class="page-header">基本使用</h1>
       <button class="btn btn-primary">发送 GET 请求</button>
       <button class="btn btn-warning">发送 POST 请求</button>
       <button class="btn btn-success">发送 PUT 请求</button>
       <button class="btn btn-danger">发送 DELETE 请求</button>
 </div>
 <script>
   const btns = document.querySelectorAll("button");
  
   //请求绑定
   btns[0].onclick = () => {
     //发送 AJAX 请求 利用axios发送
     //axios返回的是一个promise对象
     axios({
       //参数:请求类型
       method: "GET",
       //url
       url: "http://localhost:3000/posts/2",
       //还可以设置请求头信息等参数
     }).then((response) => {
       console.log(response);
     });
   };
  
   //POST请求 添加一篇新的文章
   btns[1].onclick = () => {
     //发送 AJAX 请求 利用axios发送
     //axios返回的是一个promise对象
     axios({
       //参数:请求类型
       method: "POST",
       //url
       url: "http://localhost:3000/posts",
       //还设置请求头
       data: {
         title: "sehunBBQ",
         author: "小彬",
       },
     }).then((response) => {
       console.log(response);
     });
   };
  
   //put请求更新数据
   btns[2].onclick = () => {
     //发送 AJAX 请求 利用axios发送
     //axios返回的是一个promise对象
     axios({
       //参数:请求类型
       method: "PUT",
       //url
       url: "http://localhost:3000/posts/3",
       //还设置请求头
       data: {
         title: "今天天气很好",
         author: "小彬",
       },
     }).then((response) => {
       console.log(response);
     });
   };
  
   //删除数据
   btns[3].onclick = () => {
     //发送 AJAX 请求 利用axios发送
     //axios返回的是一个promise对象
     axios({
       //参数:请求类型
       method: "DELETE",
       //url
       url: "http://localhost:3000/posts/3",
     }).then((response) => {
       console.log(response);
     });
   };
 </script>

其他使用:

基本使用

   
 <script>
   const btns = document.querySelectorAll("button");
  
   //发送get请求
   btns[0].onclick = () => {
     //axios()方法发送
     axios
       .request({
         method: "GET",
         url: "http://localhost:3000/comments",
       })
       .then((response) => {
         console.log(response);
       });
   };
  
   //发送post请求
   btns[1].onclick = () => {
     //axios()方法发送
     axios
       .post("http://localhost:3000/comments", {
         body: "hello",
         postId: 2,
       })
       .then((response) => {
         console.log(response);
       });
   };
 </script>

4、基本知识

  1. axios的默认配置

 <body>
     <div class="container">
         <h2 class="page-header">基本使用</h2>
         <button class="btn btn-primary"> 发送GET请求 </button>
         <button class="btn btn-warning" > 发送POST请求 </button>
         <button class="btn btn-success"> 发送 PUT 请求 </button>
         <button class="btn btn-danger"> 发送 DELETE 请求 </button>
     </div>
     <script>
         //获取按钮
         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].onclick = function(){
             axios({
                 url: '/posts'
             }).then(response => {
                 console.log(response);
             })
         }
  
     </script>
 </body>
  1. axios实例对象

 <body>
     <div class="container">
       <h1 class="page-header">基本使用</h1>
       <button class="btn btn-primary">发送 GET 请求</button>
       <button class="btn btn-warning">发送 POST 请求</button>
     </div>
   </body>
   <script>
     //获取按钮
     const btns = document.querySelectorAll("button");
  
     //创建实例对象
     //段子接口 https://api.apiopen.top/gegetJoke
     const passage = axios.create({
       baseURL: "https://api.apiopen.top",
       timeout: 2000,
     });
  
     const another = axios.create({
       baseURL: "https://b.cm",
       timeout: 2000,
     });
     //passage 与axios对象功能几乎是一样的
     //当做函数
     /*
     passage({
       url: "/getJoke",
     }).then((response) => {
       console.log(response);
     });
     */
  
     //借助封装好的方法
     passage.get("/getJoke").then((response) => {
       console.log(response.data);
     });
   </script>

3.axios拦截器:

请求拦截器(在发送请求前,使用函数对请求的参数和内容进行处理和检测,若请求有问题可直接进行拦截->取消,后进先执行=则后面的请求拦截器先执行)

响应拦截器(对响应的结果预处理,先进先执行=前面的响应拦截器先执行)

1)请求拦截器:

① 在真正发送请求前执行的回调函数

② 可以对请求进行检查或配置进行特定处理

③ 失败的回调函数,传递的默认是error

④ 成功的回调函数,传递的默认是config(也必须是)

2)响应拦截器

① 在请求得到响应后执行的回调函数

② 可以对响应数据进行特定处理

③ 成功的回调函数,传递的默认是response

④ 失败的回调函数,传递的默认是error

3)请求转换器:对请求头和请求体数据进行特定处理的函数

响应转换器:将响应体json字符串解析为js对象或数组的函数

4)代码

  <script>
       //设置一个请求拦截器,在请求拦截器中可以对请求参数进行修改
       //config:配置对象
       axios.interceptors.request.use(
         function (config) {
           console.log("请求拦截器 成功 1号");
           // config.headers.test = "I am only a header!";
           //修改 config 中的参数
           config.params = { a: 100 };
           return config;
         },
         (error) => {
           console.log("请求拦截器 失败 1号");
           return Promise.reject(error);
         }
       );
  
       axios.interceptors.request.use(
         function (config) {
           console.log("请求拦截器 成功 2号");
           // config.headers.test = "I am only a header!";
           //修改 config 中的参数
           config.timeout = 2000;
           return config;
         },
         (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("自定义回调处理成功的结果");
           //console.log(response);
         })
         .catch((reason) => {
           console.log(reason);
         });
     </script>

4.取消请求:终端启动是输入json-server --watch db.json -d +时间(如 -d 2000)

   <body>
     <div class="container">
       <h1 class="page-header">axios取消请求</h1>
       <button class="btn btn-primary">发送请求</button>
       <button class="btn btn-warning">取消请求</button>
     </div>
   </body>
   <script>
     //获取按钮
     const btns = document.querySelectorAll("button");
     //2.声明一个全局变量
     let cancel = null;
     //发送请求
     btns[0].onclick = () => {
       //检测上一次请求是否已经完成
       if (cancel !== null) {
         //则代表上一次请求还未取消,故直接取消上一次请求
         cancel();
       }
       axios({
         method: "GET",
         url: "http://localhost:3000/posts",
         //1.添加配置对象的属性
         cancelToken: new axios.CancelToken((c) => {
           //3.将c的值赋值给cancel
           cancel = c;
         }),
       }).then((response) => {
         console.log(response);
         //当请求执行完后 将cancel进行初始化设置
         cancel = null;
       });
     };
  
     //取消请求
     btns[1].onclick = () => {
       cancel();
     };
   </script>

5、源码

1、axios发送请求

 <script>
   //构造函数
   function Axios(config) {
     //初始化
     this.defaults = config; //为了创建default默认属性
     this.interceptors = {
       request: {},
       response: {},
     };
   }
   //原型添加相关方法
   Axios.prototype.request = function (config) {
     console.log("发送AJAX请求,请求类型为" + config.method);
   };
   Axios.prototype.get = function (config) {
     return this.request({ method: "GET" }); //在内部调用了request方法
   };
   Axios.prototype.post = function (config) {
     return this.request({ method: "POST" });
   };
  
   //声明函数
   function createInstance(config) {
     //1.实例化一个对象
     let context = new Axios(config);
     //可使用Axios中的方法 如context.get(),但是不能当做函数使用
     //创建请求对象函数
     let instance = Axios.prototype.request.bind(context);
     //instance是一个函数,可以instance({}),此时instance不能 instance.get()
     //将 Axios.prototype对象中的方法添加到instance函数中
     Object.keys(Axios.prototype).forEach((element) => {
       instance[element] = Axios.prototype[element].bind(context);
     });
     //为 instance 函数对象添加属性 default 与 interceptors
     Object.keys(context).forEach((key) => {
       //进行赋值
       instance[key] = context[key];
     });
     return instance;
   }
  
   //创建对象
   let axios = createInstance({ method: "GET" });
   //发送请求
   axios.get();
 </script>

2、axios请求发送过程

 <script>
   //axios 发送请求 axios Axios.prototype.request bind
   //1.声明构造函数
   function Axios(config) {
     this.config = config;
   }
   Axios.prototype.request = (config) => {
     //发送请求
     //创建了一个promise对象
     let promise = Promise.resolve(config);
     //声明一个数组 undefine 作用:占位
     let chains = [dispatchRequest, undefined];
     //调用then方法指定回调
     let result = promise.then(chains[0], chains[1]);
     //返回promise结果
     return result;
   };
  
   //2.dispatchRequset函数
   function dispatchRequest(config) {
     //调用适配器发送请求
     return xhrAdapter(config).then(
       (response) => {
         //对响应结果进行处理
         return response;
       },
       (error) => {
         throw error;
       }
     );
   }
  
   //3.adapter适配器
   function xhrAdapter(config) {
     return new Promise((resolve, reject) => {
       //发送AJAX请求
       let xhr = new XMLHttpRequest();
       //初始化
       xhr.open(config.method, config.url);
       //发送
       xhr.send();
       //绑定事件
       xhr.onreadystatechange = () => {
         //判断成功的条件
         if (xhr.readyState === 4) {
           if (xhr.status >= 200 && xhr.status < 300) {
             //成功的状态
             resolve({
               //配置对象
               config: config,
               //响应体
               data: xhr.response,
               //响应头
               headers: xhr.getAllResponseHeaders(), //字符串
               //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>

3、axios拦截器模拟实现

 <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>

4、axios取消请求

   <body>
     <div class="container">
       <h1 class="page-header">axios取消请求</h1>
       <button class="btn btn-primary">发送请求</button>
       <button class="btn btn-warning">取消请求</button>
     </div>
   </body>
   <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();
             //将整体结果设置为失败
             cancel = null;
             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>

 

6、总结

1.axios和Axios的关系

1)从语法上来说:axios不是Axios的实例;

2)从功能上来说:axios是Axios的实例;(因为axios拥有Axios实例对象上的方法);

3)axios是Axios.prototype.request函数bind()返回的函数;

4)axios作为对象有Axios原型对象上的所有方法,有Axios对象上的所有属性;

2.instance与axios的区别

1)相同:

① 都是一个能发任意请求的函数:request(config);

② 都有发特定请求的各种方法:get()/post()/put()/delete();

③ 都有默认配置和拦截器属性:defaults/interceptors;

2)不同:

① 默认配置可能不一样;

② instance不具备axios后面添加的一些方法:creat()/CancelToken()/all();

3.axios运行的整体流程

request(config) -> dispatchRequest(config) -> xhrAdapter(config)(适配器)

 

 

扩展

Object.keys()的详解和用法

在实际开发中,我们有时需要知道对象的所有属性; ES5 引入了Object.keys方法,成员是参数对象自身的(不含继承的)所有可遍历enumerable )属性的键名。

传入对象,返回属性名

 var data={a:1,b:2,c:9,d:4,e:5};
     console.log(Object.keys(data));//["a", "b", "c", "d", "e"]
     Object.keys(data).map((key,item)=>{
         console.log(key,data[key]);//key=>属性名    data[key]=>属性值
 });

传入字符串,返回索引

 var str = 'ab1234';
 console.log(Object.keys(obj));  //[0,1,2,3,4,5]

传入数组 返回索引

 var arr = ["a", "b", "c"];
 console.log(Object.keys(arr)); // console: ["0", "1", "2"]

构造函数 返回空数组或者属性名

 function Pasta(name, age, gender) {
       this.name = name;
       this.age = age;
       this.gender = gender;
       this.toString = function () {
             return (this.name + ", " + this.age + ", " + this.gender);
     }
 }
 ​
 console.log(Object.keys(Pasta)); //console: []
 ​
 var spaghetti = new Pasta("Tom", 20, "male");
 console.log(Object.keys(spaghetti)); //console: ["name", "age", "gender", "toString"]

扩展

Object.values()

Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历( enumerable )属性的键值。

Object.entries()

Object.entries方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历( enumerable )属性的键值对数组。

 

 

posted @ 2022-06-23 22:33  nakano_may  阅读(115)  评论(0编辑  收藏  举报