02-axios
码路教育 7/29/2022
# 1. 初识axios
axios是什么?
- 前端最流行的ajax请求库
- react/vue官方都推荐使用axios发ajax请求
- 文档: https://github.com/axios/axios
功能特点
- 基于xhr + promise的异步ajax请求库
- 浏览器端/node端都可以使用
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 支持请求取消
- 批量发送多个请求
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(): 用来指定接收所有成功数据的回调函数的方法
常见的配置选项
- 请求地址 url: '/user'
- 请求类型 method: 'get'
- 根求路径 baseURL: 'http://www.mt.com/api'
- 请求前的数据处理 transformRequest:function(data){}
- 请求后的数据处理 transformResponse: function(data){}
- 自定义的请求头 headers:{'x-Requested-With':'XMLHttpRequest'}
- URL查询对象 params:{ id: 12 }
- 查询对象序列化函数 paramsSerializer: function(params){ }
- request body data: { key: 'aa'}
- 超时设置 timeout: 1000
# 2. 发送request请求
前端代码
<!-- <script src="../node_modules/axios/dist/axios.min.js"></script> -->
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
// 利用axios发请求,得到的结果是一个promise
// 要得到成功的结果,就是需要.then
// 真实的数据是在data中,其它的数据,都是axios帮我们封装好的
// let axRes = axios.request({
// url: "http://127.0.0.1:3000/get",
// method: "get"
// })
// axRes.then(res => {
// console.log("data:", res.data);
// })
axios.request({
url: "http://127.0.0.1:3000/get",
method: "get"
}).then(res => {
console.log("data:", res.data);
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
后端代码
const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();
app.use(cors());
app.use(logger());
app.use(koaBody());
router.get("/get", async (ctx, next) => {
ctx.status = 200;
ctx.body = "hello axios";
});
app.use(router.routes())
router.allowedMethods();
app.listen(3000, () => {
console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 3. 发送get请求
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
// axios.get("http://127.0.0.1:3000/get").then(res => {
// console.log(res.data);
// })
(async function() {
let res = await axios.get("http://127.0.0.1:3000/get")
console.log(res);
})()
</script>
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
后端代码同上
# 4. 发送get请求并传参
前端代码
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
(async function() {
// query传参
// let res = await axios.get("http://127.0.0.1:3000/get?a=1&b=2")
// console.log(res.data);
// params传参
let res = await axios.get("http://127.0.0.1:3000/get", {
params: {
name: "wc",
age: 18,
address: "bj"
}
})
console.log(res.data);
})()
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
后端代码
const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();
app.use(cors());
app.use(logger());
app.use(koaBody());
router.get("/get", async (ctx, next) => {
ctx.status = 200;
ctx.body = ctx.query;
});
router.get("/get/:name/:age/:address", ctx => {
ctx.status = 200;
ctx.body = ctx.params;
})
app.use(router.routes())
router.allowedMethods();
app.listen(3000, () => {
console.log("running in http://127.0.0.1:3000");
});
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
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
# 5. 发送post请求
前端代码
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<!-- querystring -->
<script src="../node_modules/qs/dist/qs.js"></script>
<script>
(async function() {
// post传递参数
// 默认是json格式传递 Content-Type: application/json;charset=UTF-8
// let res = await axios.post("http://127.0.0.1:3000/post",{
// a:1,
// b:2,
// c:3
// })
// console.log(res.data);
// post传递参数2
// 设置请求头 axios配置请求头
// axios 是一个对象,对象也叫实例
// 默认情况下,我们可以使用人家提供给我们的实例,人家帮我们提供的实例,很多配置都是定死的
// 我们能不能自己去创建一个实例?
// 答:可以
// 如果我们想自己去配置一个更加灵活的axios实例,或我需要向不同的服务器发请求?
// 此时,我们就可以自己去创建axios实例
let res = await axios.post("http://127.0.0.1:3000/post", qs.stringify({
a: 1,
b: 2
}), {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
})
console.log(res.data);
})()
</script>
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
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
后端代码
const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();
app.use(cors());
app.use(logger());
app.use(koaBody());
router.post("/post", async (ctx, next) => {
ctx.status = 200;
ctx.body = ctx.request.body;
});
app.use(router.routes())
router.allowedMethods();
app.listen(3000, () => {
console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 6. 其它
<script>
// axios.get()
// axios.post()
// axios.request()
// ....
// axios发送多个请求
axios.all([
axios.get("http://httpbin.org/get"),
axios.post("http://httpbin.org/post")
]).then(res => {
console.log("res:", res);
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
// 设置axios的baseURL,如果设置了,后面的请求会自动添加baseURL
let baseURL = "http://httpbin.org"
axios.defaults.baseURL = baseURL;
axios.defaults.timeout = 3000; // 设置超时时间 如果超时了 自动取消请求
axios.defaults.headers = { // 给请求添加请求头
a: 1,
b: 2
}
axios.get("/get").then(res => {
console.log("res:", res);
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 7. axios的创建实例
为什么要创建axios的实例呢
- 当我们从axios模块中导入对象时, 使用的实例是默认的实例
- 当给该实例设置一些默认配置时, 这些配置就被固定下来了
- 但是后续开发中, 某些配置可能会不太一样
- 比如某些请求需要使用特定的baseURL或者timeout等
- 这个时候, 我们就可以创建新的实例, 并且传入属于该实例的配置信息
面试题
- 需求: 项目中有部分接口需要的配置与另一部分接口需要的配置不太一样, 如何处理
- 解决: 创建2个新axios, 每个都有自己特有的配置, 分别应用到不同要求的接口请求中
注意点
- 根据指定配置创建一个新的axios, 也就就每个新axios都有自己的配置
- 新axios只是没有取消请求和批量发请求的方法, 其它所有语法都是一致的
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
// axios.get
// 创建自己的实例 {}叫配置对象,这里面,就可以书写自己的配置
let axios1 = axios.create({
baseURL: "http://127.0.0.1:3000",
timeout: 3000,
headers: {}
})
axios1.get("/news", {
params: {
a: 1
}
}).then(res => {
console.log("res:", res);
})
let axios2 = axios.create({
baseURL: "http://127.0.0.1:5000",
timeout: 5000,
headers: {}
})
axios1.get("/students", {
params: {
a: 1
}
}).then(res => {
console.log("res:", res);
})
</script>
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
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
# 8. 请求和响应拦截器
axios的也可以设置拦截器:拦截每次请求和响应
- axios.interceptors.request.use(请求成功拦截, 请求失败拦截)
- axios.interceptors.response.use(响应成功拦截, 响应失败拦截)
前端代码
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
<button>发送请求</button>
<script>
let btn = document.querySelectorAll("button")[0];
// 给默认实例添加请求拦截器
// 这样写,相当于,这个拦截器什么也没有做
// axios.interceptors.request.use(config => {
// return config;
// })
// 所谓的做一些事,就是做一些配置
axios.interceptors.request.use(config => {
config.headers.Authorization = `fsadfsadf6789f87s6adf68asodfihasjkdfasdf7678fasd67f8asdfas`;
NProgress.start(); // 显示进度条
return config;
}, err => {
// 失败的回调,直接响应失败的promsie
return Promise.reject(err)
})
axios.interceptors.response.use(response => {
NProgress.done(); // 关闭进度条
return response.data; // 仅仅把data过滤出来
}, err => {
// 失败的回调,直接响应失败的promsie
return Promise.reject(err)
})
btn.onclick = function() {
axios.get("http://httpbin.org/delay/5").then(res => {
console.log(res);
})
}
</script>
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
39
40
41
42
43
44
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
39
40
41
42
43
44
面试题:拦截器函数/ajax请求/请求的回调函数的调用顺序
- 说明: 调用axios()并不是立即发送ajax请求, 而是需要经历一个较长的流程
- 流程: 请求拦截器2 => 请求拦截器1 => 发ajax请求 => 响应拦截器1 => 响应拦截器2 => 请求的回调
- 注意: 此流程是通过promise串连起来的, 请求拦截器传递的是config, 响应拦截器传递的是response
# 9. 取消请求
基本流程
- 配置cancelToken对象
- 缓存用于取消请求的cancel函数
- 在后面特定时机调用cancel函数取消请求
- 在错误回调中判断如果error是cancel, 做相应处理
实现功能:点击按钮, 取消某个正在请求中的请求
- 在请求一个接口前, 取消前面一个未完成的请求
<!-- axios源码 JS高级 -->
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<button>发送请求</button>
<button>取消请求</button>
<script>
let btns = document.querySelectorAll("button");
let cancel;
// 在请求一个接口前,取消前面没有完成的请求
btns[0].onclick = async function() {
let result = await axios("http://httpbin.org/delay/5", {
cancelToken: new axios.CancelToken(c => {
cancel = c;
})
});
console.log("result:", result);
}
btns[1].onclick = function() {
cancel(); // 手动取消上面的请求
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 10. Axios二次封装
功能点
- 统一进行请求配置: 基础路径/超时时间等
- 请求过程中loading提示
- 请求可能需要携带token数据
- 请求成功的value不再是response, 而是response.data
- 请求失败/出错统一进行处理, 每个请求可以不用单独处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script src="../node_modules/nprogress/nprogress.js"></script>
<link rel="stylesheet" href="../node_modules/nprogress/nprogress.css">
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.css" rel="stylesheet"> -->
</head>
<body>
<script>
// 一般会自己创建一个axios实例 instance是实例的意思
let instance = axios.create({
// 在这里,可以做很多配置
// baseURL是配置基础路径
baseURL: "http://127.0.0.1:3000",
timeout: 8000
})
// 目前在请求拦截器中配置了:
// 1)开启Nprogress进度条
// 2)在请求头中添加token
instance.interceptors.request.use(config => {
let token = localStorage.getItem("token") || "fasdfasdfsadf";
config.headers["token"] = token;
NProgress.start();
return config;
}, err => {
return Promise.reject(err)
})
// 目前在响应拦截器中配置了:
// 1)关闭Nprogress进度条
// 2)过滤出data数据
instance.interceptors.response.use(response => {
NProgress.done();
return response.data;
}, err => {
NProgress.done();
return Promise.reject(err)
})
// 后面发请求,就可以使用自己的实例
instance.get("http://httpbin.org/delay/5").then(res => {
console.log(res);
})
</script>
</body>
</html>
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# 11. JSONP原理
前端代码
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<button id="btn">发送ajax请求</button>
<script>
let btn = document.getElementById("btn");
function jsonp(options) {
let callBackName = "wangcai";
window[callBackName] = function(data) {
if (data != null) {
options.success(data)
} else {
options.fail()
}
}
let url = options.url + "?callBack=" + callBackName
let scriptEle = document.createElement("script");
scriptEle.src = url;
document.body.append(scriptEle)
}
btn.onclick = function() {
jsonp({
url: "http://localhost:3000/",
success: function(data) {
console.log("data:", data);
},
fail: function(err) {
console.log("数据请求失败了");
}
})
}
</script>
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
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
后端代码
const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();
app.use(cors());
app.use(logger());
app.use(koaBody());
router.get("/", (ctx) => {
let cb = ctx.query.callBack;
// console.log(cb);
// 后端返回函数调用字符串
ctx.body = `${cb}(${JSON.stringify({ a: 1, b: 2 })})`
})
app.use(router.routes())
router.allowedMethods();
app.listen(3000, () => {
console.log("running in http://127.0.0.1:3000");
});
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
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
# 12. 百度联想词案例
前端JS代码
- 其它代码不在copy
;
(function() {
// 接口地址:https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=
let searchInput = document.getElementsByClassName("J_searchInput")[0];
let wdList = document.getElementsByClassName("J_wdList")[0];
let listWrap = wdList.parentNode;
searchInput.addEventListener("input", function() {
let val = this.value.trim();
if (val.length > 0) {
getDatas(val, "setDatas");
} else {
wdList.innerHTML = "";
listWrap.style.display = "none";
}
})
// 调接口,获取数据
function getDatas(value, callbackName) {
let oScript = document.createElement("script");
oScript.src = "https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=" + value + "&cb=" + callbackName
document.body.append(oScript)
}
window.setDatas = function(data) {
// console.log("data:",data);
// render是渲染的意思 List是列表的意思
renderList(data)
}
// <li class="wd-item">
// <a href="https://www.baidu.com/s?wd={{wdLink}}" target="_blank" class="wd-lk">{{wd}}</a>
// </li>
// 渲染数据到页面上
function renderList(data) {
var data = data.s;
let len = data.length;
let list = "";
if (len) {
data.forEach(item => {
list += `
<li class="wd-item">
<a href="https://www.baidu.com/s?wd=${item}" target="_blank" class="wd-lk">${item}</a>
</li>
`
})
wdList.innerHTML = list;
listWrap.style.display = "block";
} else {
wdList.innerHTML = "";
listWrap.style.display = "none";
}
}
})()
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56