简介

Axios,是一个基于promise网络请求库,作用于node.js浏览器中,它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生node.js http模块, 而在客户端 (浏览端) 则使用XMLHttpRequests

参考资料

认识 axios

  • Axios简单的理解就是ajax的封装
  • Axios 是一个基于 promise 的 HTTP 库
  • 支持node端和浏览器端
  • 使用Promise管理异步,告别传统callback方式
  • 丰富的配置项,支持拦截器等高级配置
  • 转换请求数据和响应数据

接口案例

  • 项目的两种编程方式:模板式编程(服务端渲染好的模板返回,例如 jsp)、接口式编程(现在基本都是这种,前后端分离)
  • RestFul API 规范(URL,HTTP, 版本, 状态码, 返回值, 请求条件等规范)
    • GET(SELECT):从服务器取出资源(一项或多项)。
    • POST(CREATE):在服务器新建一个资源。
    • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。(更新表内一行的所有数据)
    • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。(更新表内一行数据的一部分字段)
    • DELETE(DELETE):从服务器删除资源。
    • 我们配置接口时,这只是一种规范,只是建议大家按照规范来使用而已。

Promise

简介

  • 主要用于异步计算
  • 可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
  • 可以在对象之间传递和操作promise,帮助我们处理队列
  • 异步回调的问题:
    • 之前处理异步是通过纯粹的回调函数的形式进行处理
    • 很容易进入到回调地狱中,剥夺了函数return的能力
    • 问题可以解决,但是难以读懂,维护困难
    • 稍有不慎就会踏入回调地狱 - 嵌套层次深,不好维护
  • promise
    • promise是一个对象,对象和函数的区别就是对象可以保存状态,函数不可以(闭包除外)
    • 并未剥夺函数return的能力,因此无需层层传递callback,进行回调获取数据
    • 代码风格,容易理解,便于维护
    • 多个异步等待合并便于解决

状态

  • Promise总共有三种状态:pending reslove reject
  • pending就是未决,resolve可以理解为成功,reject可以理解为拒绝
  • pending 可能会转变为 resolve
  • pending 也可能会转变为 reject
  • then() 函数回调后如果函数中没有发生错误会返回一个 resolve 状态的 Promise,如果回调中发生错误会返回一个 reject 状态的 Promise 然后触发 catch 的函数,同理如果 catch 中的执行没有发生错误依旧也会返回一个 resolve 状态的 Promise,还是可以走后面的 then 回调

状态及回调调用关系

回调地狱

  • 回调地狱简单说就是 套娃 请求A,但是A又依赖于B,因此在请求的A里面包含着B,同时B又依赖着C,因此B里面又包含着C,C又包含着D 这种模式就称为回调地狱

回调地狱

用法

异步

  • 任何一个 then 中如果发生错误会走 catch 的回调,这里没有定义
  • 每增加一个回调就按照这种格式写比前面的更加清晰

异步请求示例

同步

  • Promise.all 传递的参数是一个数组
  • 多个任务完成后才会触发下一个回调
  • 多个任务返回的也是一个数组

同步

axios

简介

  • axios 发起请求后返回的就是一个 Promise 对象,所以要先掌握 Promise
  • 接口是本地 mock 的一些,主要看效果

示例一

  • html 中通过 srcipt 引入 axios 方式进行测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.min.js"></script>
</head>
<body>
<script>
//第一种用法,默认请求方式为 get
axios("http://127.0.0.1:4523/mock/673120/getUser?id=1&author=ada")
.then(res => console.log(res.data))

//第二种用法 method 不传的话默认为 get
axios({
method: "get",
url: "http://127.0.0.1:4523/mock/673120/getUser",
params: {id: 1, author: "ada"}
})
.then(res => console.log(res.data))
//第三种 POST 可自己设置 headers
axios({
method: "POST",
url: "http://127.0.0.1:4523/mock/673120/getInfo",
headers: {
"content-type": "application/json"
},
data: {
cid: 10000,
region: "mock"
}
})
.then(res => console.log(res.data))
</script>
</body>
</html>

axios 示例一

线上环境使用

安装依赖

  • 上面是通过引入 js 文件方式,下面我们将通过安装 axios 依赖的方式直接使用
1
2
3
4
5
6
# npm 安装(axios 安装到线上环境) 
npm i axios -S
npm i webpack webpack-cli html-webpack-plugin -D
# yarn 安装
yarn add axios -S
yarn add webpack webpack-cli html-webpack-plugin -D

文件及配置

  • 根目录下新建 src/index.js 和 src/index.html 两个文件
  • 根目录下新建 webpack.config.js 配置文件
  • 配置 webpack
1
2
3
4
5
6
7
8
const htmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
plugins: [
new htmlWebpackPlugin({template: "./src/index.html"})
]
}

基础语法

  • index.js 的内容(新建了空的 index.html文件,webpack 打包后会引入这个 js )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import axios from "source/_posts/worker/Developer/Axios";

//get 的一般用法
axios.get("http://127.0.0.1:4523/mock/673120/getUser?id=1&author=ada")
.then(res => {
console.log(res);
})

axios.get("http://127.0.0.1:4523/mock/673120/getUser", {params: {id: 1}})
.then(res => {
console.log(res);
})

//post 的一般用法
axios.post("http://127.0.0.1:4523/mock/673120/getInfo", "cid=10000&region=mock")
.then(res => {
console.log(res);
})

示例返回

并发

  • axios 的并发和 Promise的同步是一样的 axios.all Promise.all 请求参数都是一个数据,返回也是一个数据
  • axios.spread 方法可以用参数分别接收每一个请求的结果,参数个数和发起的请求个数一致
  • ajax请求过多对页面性能可能会有影响,以及代码不美观,代码过于臃肿,所以我们可以使用 axios的并发请求axios.all()
  • axios.all() 这个方法在 axios 的构造函数是没有的,没在实例对象上。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import axios from "source/_posts/worker/Developer/Axios";

axios.all([
axios.get("http://127.0.0.1:4523/mock/673120/getUser?id=1&author=ada"),
axios.get("http://127.0.0.1:4523/mock/673120/getUser", {params: {id: 1}}),
axios.post("http://127.0.0.1:4523/mock/673120/getInfo", "cid=10000&region=mock")
])
.then(res => {
console.log("--------------------all_res--------------------");
console.log(res);
})
.catch(err => {
console.log(err);
})

axios.all([
axios.get("http://127.0.0.1:4523/mock/673120/getUser?id=1&author=ada"),
axios.get("http://127.0.0.1:4523/mock/673120/getUser", {params: {id: 1}}),
axios.post("http://127.0.0.1:4523/mock/673120/getInfo", "cid=10000&region=mock")
])
.then(axios.spread((res1, res2, res3) => { //上面是所有返回的结果是一个数组,这里用 axios.spread 用三个参数分别接收每一个请求的结果
console.log("--------------------res1 res2 res3--------------------");
console.log(res1);
console.log(res2);
console.log(res3);
}))
.catch(err => console.log(err))

并发

全局环境配置

  • axios.defaults 可配置全局环境,这里简单提取两个baseURL timeout 还有很多可扩展
  • axios.default.headers.post[‘content-type’]=’application/x-www-form-urlencoded’;
  • 整理数据
1
2
3
4
5
# 整理数据
axios.defaults.transformRequest = function (data) {
data = JSON.stringify(data);
return data;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
axios.defaults.baseURL = "http://127.0.0.1:4523/mock/673120";
axios.defaults.timeout = 5000;

axios.get("getUser?id=123&author=ada")
.then(res => {
console.log(res);
})

axios.post("getInfo", "cid=10000&region=mock")
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err);
});

实例封装

简介

  • 有时候后台接口地址有多个并且超时时长不一样,我们不可能在axios中把每个后台请求的域名地址都拼接在URl中,并且在axios中的config写不同的超时时长,很繁琐,这个时候可以用到axios实例,在实例中可以配置这两种参数。
  • 如果新建了一个axios实例但是没有参数,取得就是全局的配置值,实例中如果有则优先取实例中的
  • axios实例的相关配置(config参数)
    • baseURL:请求的域名基本地址(如:http://localhost:8080)
    • timeout:后端定义的超时时长(默认是1000ms)
    • url:请求的路径(如:/data.json)
    • method:请求方法(get、post…..)
    • headers:设置请求头
    • params:请求的参数拼接在url中
    • data:请求的参数放在request body中

创建实例

  • 如果同时定义了 axios.defaults 和实例中定义了同样的优先会用实例自己的
  • 如果实例中没有定义会使用 axios.defaults 的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let user = axios.create({
baseURL: "http://127.0.0.1:4523/mock/673120",
timeout: 2000,
});

let getUser = axios.create({
baseURL: "http://127.0.0.1:4523/mock/673120/getUser",
timeout: 2000,
method: "get",
});

let info = axios.create({
baseURL: "http://127.0.0.1:4523/mock/673120",
timeout: 3000,

})


user.get("getUser?id=111&author=ada")
.then(res => {
console.log(res)
})

info.post("getInfo", "cid=10000&region=mock")
.then(res => {
console.log(res)
})

getUser({
params: {id: 123, author: "阿达"}
})
.then(res => {
console.log(res);
})

创建实例

拦截器

示例

  • 拦截器分为请求拦截器 和响应拦截器
  • 实际用途:①请求拦截器:比如为每个请求都带上的参数,比如token,时间戳等 ②响应拦截器:比如对返回的状态进行判断,如token是否过期
  • 拦截器可以为整个 axios 设置,也可以针对具体的某个实例进行设置
  • 在使用拦截器的时候 响应拦截器可以进行设置只放行状态为 200 的,并且只放行 data(我们只return data数据)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import axios from "source/_posts/worker/Developer/Axios";

let getUser = axios.create({
baseURL: "http://127.0.0.1:4523/mock/673120/getUser",
timeout: 2000,
method: "get",
});

let info = axios.create({
baseURL: "http://127.0.0.1:4523/mock/673120",
timeout: 3000,
})

info.interceptors.request.use(config => {
console.log("info 请求拦截的配置和操作比如添加 token onFulfilled 状态");
return config; // 一定要加这个 放行 不然就截住了请求
}, err => {
console.log("info 请求拦截失败了会走下面这个代码块 onRejected 状态");
})

info.post("getInfo", "cid=10000&region=mock")
.then(res => {
console.log(res)
})

getUser.interceptors.response.use(config => {
console.log("getUser onFulfilled 状态 响应拦截的配置和操作比如只放行状态码为 200 的 ");
// 返回时也一定要放行,而且可以只放行 data 下的内容(这个里面才是接口返回的数据),不然就截住了返回的数据了 前端就拿到接口返回的数据
return config.data;
}, err => {
console.log("getUser 响应拦截失败了会走下面这个代码块 onRejected 状态");
})
getUser({
params: {id: 123, author: "阿达"}
})
.then(res => {
console.log(res);
})

拦截器

扩展

  • 一些常用的配置 添加 token 和返回状态的设置(全局 axios 有效)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 请求拦截器
axios.interceptors.request.use(
config => {
// 每次发送请求之前判断是否存在token
// 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
const token = window.localStorage.getItem("token");
token && (config.headers.Authorization = token);
return config;
},
error => {
return Promise.error(error);
}
);


axios.interceptors.response.use(
response => {
// 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
// 否则的话抛出错误
if (response.status === 200) {
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
},
// 服务器状态码不是2开头的的情况
// 这里可以跟你们的后台开发人员协商好统一的错误状态码
// 然后根据返回的状态码进行一些操作,例如登录过期提示,错误提示等等
// 下面列举几个常见的操作,其他需求可自行扩展
error => {
if (error.response.status) {
return Promise.reject(error.response);
}
}
);