axios-引入-常用语法-源码

2 篇文章 0 订阅

axios

1 axios的引入

1.1. axios是什么?

  1. 前端最流行的ajax请求库

  2. react/vue官方都推荐使用axios发ajax请求

  3. 文档: https://github.com/axios/axios

1.2. axios特点

  1. 基于xhr + promise的异步ajax请求库
  2. 浏览器端/node端都可以使用
  3. 支持请求/响应拦截器
  4. 支持请求取消
  5. 请求/响应数据转换
  6. 批量发送多个请求

1.3 axios引入

引入:npm init -y

安装:npm install axios

使用中引入axios

方法一:

  • 安装好以后回生成node_modules文件夹,在当前目录下直接引入./node_modules/axios/dist/axios.min.js

方法二:

  • 在猫云下搜索axios,复制链接引入

2 axios的基本使用

创建站点服务data.json,打开小黑屏

json-server data.json -w -p 8090 -H 127.0.0.1

共同点:都需要传参 都是有请求地址 返回数据

2.1 get获取数据

使用params 将对象转化为字符串,和地址进行拼接

	 	btns[0].onclick = async function() {
            // const result = axios.get("http://127.0.0.1/scoreList",{
            //     params:{
            //         sex:"男"
            //     }
            // })
            // // result.then(value=>{
            // //     console.log(value.data)
            // // })
            // 或者用解构赋值
            // result.then(({data})=> {
            //     console.log(data)
            // })
            // 使用await
            const {data} = await axios.get("http://127.0.0.1/scoreList", {
                params:{
                    age:12
                }
            })
            console.log(data)
        }

2.2 post添加数据

闪退更新的问题,新建server,创建express

const express = require("express");
const app = express();
app.use(eapress.static(__dirname))
app.listen(80,function() {
    console.log("success")
})

**注意:**服务端访问的地址要为localhost下默认地址

当第二个参数是对象时:content-type,application/json 传递的参数是对象

		btns[1].onclick = async function() {
            const result = await axios.post("http://localhost:3000/scoreList", {
                userName:"zhangsan"
            }) 
            console.log(result.data)
        }

当第二个参数是字符串时:content-type,application/x-www-form-urlencoded 传递的参数是字符串

 		btns[1].onclick = async function() {
            const result = await axios.post("http://localhost:3000/scoreList","age=100")
            console.log(result.data)
        }

2.3 put更新数据(完整)

		btns[2].onclick = async function() {
            const result = await axios.put("http://127.0.0.1:3000/scoreList/8",{
                userName:"laodai"
            })
            console.log(result.data)
        }

2.4 patch 更新数据(局部)

		btns[3].onclick = async function() {
            const result = await axios.patch("http://127.0.0.1:3000/scoreList/7",{
                    userName:"laoqian"
            })
            console.log(result.data)
        }

2.5 delete删除数据

		btns[4].onclick = async function() {
            const result = await axios.delete("http://127.0.0.1:3000/scoreList/11",{
                userName:"zhangsan"
            })
            console.log(result.data)
        }

2.6 head获取数据(get)

head有priview和response内容的显示

head得不到响应的内容,用于验证请求资源是否存在

2.7 axios 是一个函数

不写method 等于axios.get()

写method 等于axios.post()

测试timeout,json-server --watch data.json --delay 3000 延迟三秒反应

	axios({
            method:"post",
            url:"http://127.0.0.1:3000/scoreList",
            data:"a=1&b=2",//放置到请求体当中
            params:{
                c:3
            },//转化为字符串和地址进行拼接
            headers:{
                authorization:"abxfde"
            },
            timeout:1000
        }).then(value=>{
            console.log(value)
        }).catch(err=>{
            console.log(111,err)
        })

2.8 通过xhr模拟axios(了解)

axios是一个函数 模拟axios() axios.get() axios.post()

function axios(options={}){
    let {method="get",data="",url="",params={}} = options;
    return new Promise(function (resolve,reject) {
        const xhr = new XMLHttpRequest();
        xhr.responseType="json";
        if(options.timeout)
            xhr.timeout = options.timeout;// 增加超时设置

        // {c:3,d:4}   http://localhost:3000/scoreList
        // http://localhost:3000/scoreList?c=3&d=4
        // [c=3,d=4]
        url=url+(url.includes("?")?"&":"?")+Object.keys(params).map(v=>v+"="+params[v]).join("&")
        xhr.open(method,url);
        if(method.toLowerCase() === "post"){
            if(typeof data === "object"){
                xhr.setRequestHeader("content-type","application/json");
                xhr.send(JSON.stringify(data));
            }
            else{
                xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
                xhr.send(data);
            }

        }else{
            xhr.send();
        }
        xhr.ontimeout = function(){
            reject("请求超时");
        }

        xhr.onload = function () {
            resolve({
                // 配置对象
                config:options,
                // 响应体的内容,格式 json
                data:xhr.response,
                // 响应头的内容
                headers:xhr.getAllResponseHeaders(),
                // 发起请求的xhr实例
                request:xhr,
                // 得到的状态码
                status:xhr.status,
                // 得到的状态码说明
                statusText:xhr.statusText
            });
        }
    })
}
axios.get = function (url,config) {
    return axios({
        method:"get",
        url,
        params:config.params
    })
}
axios.post = function (url,data) {
   return  axios({
        method:"post",
        url,
        data
    })
}

2.9 axios实例

当项目当中请求接口在不同的服务器时,可以通过create创建axios实例

		const a1 = axios.create({
            baseURL:"http://localhost:3000",
            timeout:1000,
        })
        const a2 = axios.create({
            baseURL:"http://127.0.0.1:3000",
        })
        a1({
            method:"post",
            url:"/scoreList"
        })
        a2.get("/scoreList")

3 axios常用语法

3.1 数据的请求与响应的转换

transformRequest:请求时发送的数据,该函数返回的值,才是真正发送的数据,,返回的内容其实是传递给了xhr.send() 将请求的数据进行二次设置

		axios ({
            method:"post",
            url:"http://127.0.0.1:3000/scoreList",
            data:{
                a:1,
                b:2
            },
            trandformRequest(data,headers) {//post put patch 中实现
                data = {
                    ...data,
                    c:100
                }
            headers["Content-Type"]="application/json"
            return JSON.stringify(data)  //相当于send当中的内容
            }
        }).then(value=>{
            console.log(value)
        })

transformResponse:处理响应的数据,res是响应体的内容,返回的结果,才是真正得到的数据

 		// 处理响应的数据,res是响应体的内容。
            transformResponse(res){
                // 返回的结果 ,即是真正得到的数据(data)
                // const {ok,msg} =  JSON.parse(res);
                // if(ok === -1){
                //     alert(msg);
                // }
                return JSON.parse(res);
            }

3.2 默认配置

设置默认项

 		axios.defaults.baseURL = "http://localhost:3000";
        axios.defaults.headers["abcdefg"] = "11111";
        axios.defaults.timeout= 1000;
        axios.get("/scoreList")

3.3 拦截器(重要)

① 请求拦截

axios.interceptors.request.use():发送请求之前执行, 拦截函数会被执行,接收的是axios配置对象

			// 请求拦截:发送请求之前执行
        	axios.interceptors.request.use(function(config) {
            // 拦截函数会被执行,接收的是axio配置对象(config)
            config.params.sex = "男"//拦截的时候可以进行更改 没有return救护报错
            return config;//拦下什么也没干
        })

注意:请求拦截接定义多次,先定义的后执行

② 响应拦截

axios.interceptors.response.use() axios得到响应后,会执行响应拦截。返回的内容就是响应之后得到的数据

 		axios.interceptors.response.use(function(res) {
            console.log(res)  //res的响应内容
            return res.data;//返回的内容就是响应之后的数据   没有return得到的就是undefined
        })

注意:响应拦截如果写多个,先定义的先执行

请求拦截和响应拦截也具有异常穿透的功能,因为它是由若干个promise组成的

axios是基于promise通过xhr发送请求

axios.interceptors.request.eject() :取消请求拦截 (通过下标来进行取消)

axios.interceptors.response.eject() :取消响应拦截

3.4 all

用于批量执行多个异步请求

加上拦截器,输出的是一个数组

  		axios.interceptors.response.use(function(res) {
           axios.get("http://127.0.0.1:3000/scoreList",{
                params:{
                    sex:"男"
                }
            }).then(data=>{
                console.log(data)
            })
            axios.get("http://127.0.0.1:3000/scoreList",{
                params:{
                    sex:"男"
                }
            }).then(data=>{
                console.log(data)
            })
        })
	// 将两者合并
        const a1 = axios.get("http://127.0.0.1:3000/scoreList",{params:{sex:}})
        const a1 = axios.get("http://127.0.0.1:3000/scoreList",{params:{sex:}})
        axios.all([a1,a2]).then(value=>{
            console.log(value)
        })

all原理

 		function myAxios(){
        
        }
        myAxios.all = function (aArr) {
            return Promise.all(aArr);
        }
        
        myAxios.all([a1,a2]).then(value=>{
            console.log(value);
        })

3.5 spread

用来指定接收所有成功数据的回调函数的方法

const a1 = axios.get("http://localhost:3000/scoreList",{params:{sex:"男"}});
const a2 = axios.get("http://localhost:3000/scoreList",{params:{sex:"女"}});
axios.all([a1,a2]).then(axios.spread(function (one,two) {
console.log(one,two);
}));

spread原理

 		function spread(cb){
            return function (value) {// 成功
                // console.log("成功回调",value)
                // cb(value[0],value[1])
                // cb(...value);
                cb.apply(null,value);// cb.apply(null,[1,2])
            }
        }

3.6 取消请求

axios.Cancel():用于创建取消请求的错误对象

axios.CancelToken() : 用于创建取消请求的token对象

axios.isCancel(): 是否是一个取消请求的错误

  1. 基本流程

    配置cancelToken对象

    缓存用于取消请求的cancel函数

    在后面特定时机调用cancel函数取消请求

    在错误回调中判断如果error是cancel, 做相应处理

  2. 实现功能

    点击按钮, 取消某个正在请求中的请求

    在请求一个接口前, 取消前面一个未完成的请求

 	const btns = document.querySelectorAll("button")
        let cancelFn = null;
        btns[0].onclick = function () {
            if (cancelFn instanceof Function) {
                cancelFn();
            }
        axios.get("http://127.0.0.1:3000/scoreList",{
            params:{
                sex:"男"
            },
        cancelToken:new axios.CancelToken(function(cb) {
            cancelFn = cb
        }),
        timeout:3000//json-server --watch data.json --delay 3000  延迟三秒反应 
        }).then(value=>{
            console.log(value)
        }).catch(err=>{
            console.log(axios.isCancel(err))//  判断错误信息是否为取消请求造成的。true
        })
        }
		btns[1].onclick = function () {
   		cancelFn("取消请求")
}

取消原理

 const btns = document.querySelectorAll("button");
    let cancelFn = null;
    function axios(config){
        return new Promise((resolve,reject)=>{
            const xhr = new XMLHttpRequest();
            xhr.open("get",config.url);
            xhr.send();
            xhr.onload = function () {
                resolve(JSON.parse(xhr.responseText));
            }
            xhr.onabort = function () {
                reject("取消请求")
            }
            if(config.cancelToken){
                config.cancelToken.cancel.then(value=>{
                    // console.log("执行了")
                    xhr.abort();// 取消请求
                })
            }
        })
    }
    axios.CancelToken = function(callback){
        this.cancel = new Promise(resolve=>{
            callback(resolve)
        })
    }
    btns[1].onclick = function(){
        cancelFn()
    }
    btns[0].onclick = function () {
        axios({
            url:"http://localhost:3000/scoreList",
            cancelToken:new axios.CancelToken(function (cb) {
                cancelFn=cb;
            })
        }).then(value=>{
            console.log(value);
        }).catch(err=>{
            console.log("异常",err);
        })
    }

3 axios的理解

3.1. axios常用语法总结

axios(config): 通用/最本质的发任意类型请求的方式

axios(url[, config]): 可以只指定url发get请求

axios.request(config): 等同于axios(config)

axios.get(url[, config]): 发get请求

axios.delete(url[, config]): 发delete请求

axios.post(url[, data, config]): 发post请求

axios.put(url[, data, config]): 发put请求

axios.defaults.xxx: 请求的默认全局配置

axios.interceptors.request.use(): 添加请求拦截器

axios.interceptors.response.use(): 添加响应拦截器

axios.create([config]): 创建一个新的axios(它没有下面的功能)

axios.Cancel(): 用于创建取消请求的错误对象

axios.CancelToken(): 用于创建取消请求的token对象

axios.isCancel(): 是否是一个取消请求的错误

axios.all(promises): 用于批量执行多个异步请求

axios.spread(): 用来指定接收所有成功数据的回调函数的方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gsaDLL5B-1621944122791)(file:///C:\Users\王秀\AppData\Local\Temp\ksohtml3944\wps4.png)]

工厂对象:调用方提供或者有默认值,直接调用

creat是axios下的属性和方法,两者都是函数

3.2. 难点语法的理解和使用

3.2.1. axios.create(config)

  1. 根据指定配置创建一个新的axios, 也就就每个新axios都有自己的配置

  2. 新axios只是没有取消请求和批量发请求的方法, 其它所有语法都是一致的

  3. 为什么要设计这个语法?

(1) 需求: 项目中有部分接口需要的配置与另一部分接口需要的配置不太一样, 如何处理

(2) 解决: 创建2个新axios, 每个都有自己特有的配置, 分别应用到不同要求的接口请求中

3.2.2 拦截器函数/ajax请求/请求的回调函数的调用顺序

  1. 说明: 调用axios()并不是立即发送ajax请求, 而是需要经历一个较长的流程

  2. 流程: 请求拦截器2 => 请求拦截器1 => 发ajax请求 => 响应拦截器1 => 响应拦截器2 => 请求的回调

  3. 注意: 此流程是通过promise串连起来的, 请求拦截器传递的是config, 响应拦截器传递的是response

  4. 请求以及响应拦截是可以写多个的,请求拦截先定义后执行,响应拦截先定义先执行

4 axios源码分析

4.1. 源码目录结构

├── /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                   # 入口文件

4.2 源码分析

4.2.1. axios与Axios的关系?

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

  2. 从功能上来说: axios是Axios的实例

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

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

4.2.2. instance与axios的区别?

  1. 相同:

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

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

(3) 都有默认配置和拦截器的属性: defaults/interceptors

  1. 不同:

(1) 默认配置很可能不一样

(2) instance没有axios后面添加的一些方法: create()/CancelToken()/all()

4.2.3. axios运行的整体流程?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WWeVGs13-1621944122795)(file:///C:\Users\王秀\AppData\Local\Temp\ksohtml3944\wps6.png)]

  1. 整体流程:

request(config) ==> dispatchRequest(config) ==> xhrAdapter(config)

  1. request(config):

将请求拦截器 / dispatchRequest() / 响应拦截器 通过promise链串连起来, 返回promise

  1. dispatchRequest(config):

转换请求数据 ===> 调用xhrAdapter()发请求 ===> 请求返回后转换响应数据. 返回promise

  1. xhrAdapter(config):

创建XHR对象, 根据config进行相应设置, 发送特定请求, 并接收响应数据, 返回promise

4.2.4. axios的请求/响应拦截器是什么?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O7K4tOi0-1621944122798)(file:///C:\Users\王秀\AppData\Local\Temp\ksohtml3944\wps7.png)]

  1. 请求拦截器:

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

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

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

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

  1. 响应拦截器

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

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

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

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

4.2.5. axios的请求/响应数据转换器是什么?

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

if (utils.isObject(data)) {

setContentTypeIfUnset(headers, ‘application/json;charset=utf-8’);

return JSON.stringify(data);

}

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

response.data = JSON.parse(response.data)

4.2.6. response的整体结构

{

​ data,

​ status,

​ statusText,

​ headers,

​ config,

​ request

}

4.2.7. error的整体结构

{

​ message,

​ response,

​ request,

}

4.2.8. 如何取消未完成的请求?

  1. 当配置了cancelToken对象时, 保存cancel函数

(1) 创建一个用于将来中断请求的cancelPromise

(2) 并定义了一个用于取消请求的cancel函数

(3) 将cancel函数传递出来

  1. 调用cancel()取消请求

(1) 执行cacel函数, 传入错误信息message

(2) 内部会让cancelPromise变为成功, 且成功的值为一个Cancel对象

(3) 在cancelPromise的成功回调中中断请求, 并让发请求的proimse失败, 失败的reason为Cancel对象

源码分析代码:

	function Axios(config){

    }
    Axios.prototype.request = function () {

    }
    Axios.prototype.get = function () {

    }
    Axios.prototype.post = function () {

    }

    function createInstance(defaultConfig) {
        // 实例化Axios,将默认参数(defaultConfig)进行传递
        var context = new Axios(defaultConfig);
        //将content(Axios的实例)当中的属性以及方法放置到request当中
        var instance = Axios.prototype.request.bind(context);
        // Copy axios.prototype to instance
        // instance:request函数(this指向到axios实例) ,原型对象,axios实例
        // 直白:将Axios原型对象当中的属性和方法,复制到了request函数对象中。
        Object.keys(Axios.prototype).forEach(key=>{
            if(Axios.prototype[key] instanceof  Function){
                instance[key] = Axios.prototype[key].bind(context);
            }else{
                instance[key]=  Axios.prototype[key];
            }

        })

        Object.keys(context).forEach(key=>{
            if(context[key] instanceof Function){
                instance[key]= context[key].bind(context);
            }else{
                instance[key] = context[key];
            }
        })

        return instance;
    }
    const axios = createInstance({});

4.3. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UidG0Yg0-1621944122800)(file:///C:\Users\王秀\AppData\Local\Temp\ksohtml3944\wps8.png)]Axios二次封装

4.3.1. 功能点

  1. 统一进行请求配置: 基础路径/超时时间等

  2. 请求过程中loading提示

  3. 请求可能需要携带token数据

  4. 请求成功的value不再是response, 而是response.data

  5. 请求失败/出错统一进行处理, 每个请求可以不用单独处理

4.3.2. 编码实现与测试

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Axios二次封装</title>
  <link rel="stylesheet" href="https://cdn.bootcss.com/nprogress/0.2.0/nprogress.css">
</head>
<body>

<div>
  <button onclick="getUsers()">获取用户列表</button>
  <button onclick="getRepos()">获取仓库列表</button>
</div>
  
  <!-- 
    测试接口1: https://api.github.com/search/repositories?q=v&sort=stars
    测试接口1: https://api.github.com/search/users?q=v
  -->
  <!--
   1). 统一进行请求配置: 基础路径/超时时间等
   2). 请求过程中loading提示
   3). 请求可能需要携带token数据
   4). 请求成功的value不再是response, 而是response.data
   5). 请求失败/出错统一进行处理, 每个请求可以不用单独处理
  -->

  <script src="https://cdn.bootcss.com/axios/0.19.0/axios.js"></script>
  <script src="https://cdn.bootcss.com/nprogress/0.2.0/nprogress.js"></script>
  <script>
    const instance = axios.create({
      baseURL: 'https://api.github.com',
      timeout: 15000
    })

    instance.interceptors.request.use(config => {
      NProgress.start()
      // 从local中读取前面保存的token数据
      const token = localStorage.getItem('token_key') || 'xxxxx'
      if (token) {
        config.headers['token'] = token  // 请求头的名称为后台接口指定
      }

      return config
    })

    instance.interceptors.response.use(
      response => {
        NProgress.done()
        return response.data
      },
      error => {
        NProgress.done()
        alert('请求出错了', error)
        return error
      }
    )
  </script>

  <script>
    function getUsers () {
      instance.get('/search/users', {
        params: {
          q: 'v'
        }
      }).then(result => {
        console.table(result.items)
      })
    }

    function getRepos () {
      instance.get('/search/repositories', {
        params: {
          q: 'v',
          sort: 'stars'
        }
      }).then(result => {
        console.table(result.items)
      })
    }
  </script>
</body>
</html>
 const token = localStorage.getItem('token_key') || 'xxxxx'
  if (token) {
    config.headers['token'] = token  // 请求头的名称为后台接口指定
  }

  return config
})

instance.interceptors.response.use(
  response => {
    NProgress.done()
    return response.data
  },
  error => {
    NProgress.done()
    alert('请求出错了', error)
    return error
  }
)
```
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值