# axios

HTTP 相关

MDN 文档

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Overview

HTTP 请求基本过程

1657174160694

  • 01 浏览器端向服务器发送 HTTP 请求(请求报文)
  • 02 后台服务器接收到请求后,处理请求,向浏览器端返回 HTTP 响应(响应报文)
  • 03 浏览器端接收到响应,解析显示响应体调用回调函数

HTTP 请求报文

请求行

  • 格式 : method url
  • 例如 : GET /product_detail?id=2 或 POST /login

请求头

  • Host: www.baidu.come
  • Cookie: BAIDUID=AD3B0FA706E; BIDUPSID=AD3BOFA706;
  • Content-Type: application/x-www-form-urlencoded 或者 application/json

请求体

  • username=tom&pwd=123
  • {“username”: “tom”, “pwd”: 123}
  • get 请求没有请求体

HTTP 响应报文

响应行

  • 格式: status statusText
  • 例如: 200 OK 或 404 Not Found

响应头

  • Cortent-Type: text/html;charset=utf-8
  • Set-Cookie: BD_CK_SAM=1;path=/

响应体

  • html/ljson/js/css/图片..

常见的响应状态码

  • 200 OK 请求成功。一般用于 GET 与 POST 请求
  • 201 Created 已创建。成功请求并创建了新的资源
  • 401 Unauthorized 未授权 / 请求要求用户的身份认证
  • 404 Not Found 服务器无法根据客户端的请求找到资源
  • 500 Internal Server Error 服务器内部错误,无法完成请求

请求方式

  • 01 GET (索取) : 从服匀器端读取数据—–查(R)

  • 02 POST (交差) : 向服务器端添加新数据——增(C)

  • 03 PUT : 更新服务器端已存在的数据——-改(U)

  • 04 DELETE : 删除服务器端数据———删(D)

请求参数

query 参数

  • 01 参数包含在请求地址中,格式为: /xxxx?name=tom&age=18
  • 02 敏感数据不要用 query 参数,因为参数是地址的一部分,比较危险,比如用户密码。
  • 03 备注: query 参数又称查询字符串参数,编码方式为 urlencoded

params 参数

  • 01 参数包含在请求地址中,格式: http://localhost:3000/add_person/tom/18

  • 02 敏感数据不要用 params 参数,因为参数是地址的一部分,比较危险。比如用户密码。

请求体参数

  • 01 参数包含在请求体中,可通过浏览器开发工具查看

  • 02 常用的两种格式:

    • 格式一: urlencoded 格式
    • 例如: name=tom&age=18
    • 对应请求头:Content-Type: application/x-www-form-urlencoded
  • 格式二: json 格式

    • 例如: {“name”: “tom”, “age”: 12}
    • 对应请求头: Content-Type: application/jsone

注意点

  • 01 GET 请求不能携带请求体参数,因为 GET 请求没有请求体。
  • 02 理论上一次请求可以随意使用上述 3 种类型参数中的任何一种,甚至一次请求的 3 个参数可以用 3 种形式携带,但一般不这样做。
  • 03 一般来说我们有一些“约定俗成”的规矩:
    • (1) 例如 form 表单发送 post 请求时:自动使用请求体参数,用 urlencoded 编码。
    • (2) 例如 jQuery 发送 ajax-post 请求时:自动使用请求体参数,用 urlencoded 编码。
  • 04 开发中请求到底发给谁?用什么请求方式?携带什么参数?—-要参考项目的 API 接口

API 相关

API 分类

  • 01 REST API
    • restful 风格的 API
    • 发送请求进行 CRUD , 哪个操作由请求方式来决定
    • 同一个请求路径可以进行多个操作
    • 请求方式会用到 GET / POST / PUT / DELETE
  • 02 非 REST API
    • restless 风格的 API
    • 请求方式不决定请求的 CRUD 操作
    • 一个请求路径只对应—个操作
    • 一般只有 GET / POST

json-server 的使用

    1. 安装 json-server
1
npm install -g json-server
    1. 启动服务,会默认创建 db.json 文件
1
json-server --watch db.json

postman 测试接口

一般 http 请求与 ajax 请求

  • 01 ajax 请求是一种特别的 http 请求
  • 02 对服务器端来说,没有任何区别,区别在浏览器端
  • 03 浏览器端发请求: 只有 XHR 或 fetch 发出的才是 ajax 请求,其它所有的都是非 ajax 请求
  • 04 浏览器端接收到响应
    • (1) 一般请求:浏览器一般会直接显示响应体数据,也就是我们常说的自动刷新 / 跳转页面
    • (2) ajax 请求:浏览器不会对界面进行任何更新操作,只是调用监视的回调函数并传入响应相关数据

03 axios

axios 是什么

axios 特点

  • 01 基本 promise 的异步 ajax 请求库
  • 02 浏览器端 / node 端都可以使用
  • 03 支持请求 / 响应拦截器
  • 04 支持请求取消
  • 05 请求 / 响应数据转换
  • 06 批量发送多个请求

使用 axios 发起 ajax 请求

  • 01 axios 调用的返回值是 Promise 实例对象。

  • 02 成功的值叫 response,失败的值叫 error

  • 03 axios 成功的值是一个 axios 封装的 response 对象,服务器返回的真正数据在 response.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
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.0.0-alpha.1/axios.min.js"></script>

<body>
<button id="btn1">按钮</button>
<script>
// 获取按钮
const btn1 = document.getElementById('btn1')
// 发送get请求-不携带参数
btn1.onclick = () => {
axios({
url: 'http://localhost:5000/persons', //请求地址
method: 'GET', //请求方法
}).then(
(response) => {
// 成功时执行的回调
console.log('请求成功了', response.data)
},
(error) => {
// 失败时执行的回调
console.log('请求失败了', error)
}
)
}
</script>
</body>
  • 精简写法
1
2
3
4
5
6
7
8
9
10
11
btn1.onclick = () => {
// 精简写法
axios.get('http://localhost:5000/persons').then(
(response) => {
console.log('请求成功了', response.data)
},
(error) => {
console.log('请求失败了', error)
}
)
}
  • 精简写法
1
2
3
4
5
btn1.onclick = async () => {
// 精简写法
const result = await axios.get('http://localhost:5000/persons')
console.log(result.data)
}

携带 query 参数发 get 请求

  • 完整写法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
btn2.onclick = () => {
// 完整版 -- 携带参数
axios({
url: 'http://localhost:5000/person', //请求地址
method: 'GET', //请求方法
params: { id: personId.value }, // 此处写的是 params,但携带的是query参数, params参数在url中拼接
}).then(
(res) => {
console.log('请求成功了', res.data)
},
(err) => {
console.log('请求失败了', err)
}
)
}
  • 精简写法
1
2
3
4
5
6
7
8
9
10
11
12
btn2.onclick = () => {
// 精简版
// 此处写的是params,但携带的是query参数,params参数在url中拼接
axios.get('http://localhost:5000/person', { params: { id: personId.value } }).then(
(res) => {
console.log('请求成功了', res.data)
},
(err) => {
console.log('请求失败了', err)
}
)
}

携带请求体参数发起 post 请求

  • axios 底层把 post 请求也封装成了复杂请求,在真正发起请求之前,会发起嗅探请求

  • 完整写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
btn3.onclick = () => {
// 完整版 -- 携带参数
axios({
url: 'http://localhost:5000/person', //请求地址
method: 'POST', //请求方法
// data: { name: personName.value, age: personAge.value } //携带请求体参数,json 编码
data: `name=${personName.value}&age=${personAge.value}`, // 携带请求体参数,urlencoded 编码
}).then(
(res) => {
console.log('请求成功了', res.data)
},
(err) => {
console.log('请求失败了', err)
}
)
}
  • 精简写法:
1
2
3
4
5
6
7
8
9
10
11
12
btn3.onclick = () => {
// 精简版
// 携带请求体参数,用 json编码 如要使用 urlencoded编码,第二个参数直接用字符串模板拼串即可
axios.get('http://localhost:5000/person', { name: personName.value, age: personAge.value }).then(
(res) => {
console.log('请求成功了', res.data)
},
(err) => {
console.log('请求失败了', err)
}
)
}

携带请求体参数发起 PUT 请求

  • 完整写法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
btn4.onclick = () => {
// 完整版 -- 携带参数
axios({
url: 'http://localhost:5000/person', //请求地址
method: 'PUT', //请求方法
data: {
id: personUpdateID.value,
name: personUpdateName.value,
age: personUpdateAge.value,
}, //携带请求体参数,json编码
}).then(
(res) => {
console.log('请求成功了', res.data)
},
(err) => {
console.log('请求失败了', err)
}
)
}
  • 精简写法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
btn4.onclick = () => {
// 精简版
// 携带请求体参数,用 json编码 使用 urlencoded编码,第二个参数直接用字符串模板拼串即可
axios
.put('http://localhost:5000/person', {
id: personUpdateID.value,
name: personUpdateName.value,
age: personUpdateAge.value,
})
.then(
(res) => {
console.log('请求成功了', res.data)
},
(err) => {
console.log('请求失败了', err)
}
)
}

携带 params 参数发起 delete 请求

1
2
3
4
5
6
7
8
9
10
11
12
13
btn5.click = () => {
axios({
url: `http://localhost:5000/person/${personDeleteId.value}`, //请求地址,携带params参数
method: 'DELETE', //请求方法
}).then(
(res) => {
console.log('请求成功了', res.data)
},
(err) => {
console.log('请求失败了', err)
}
)
}

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
// 给 axios 配置默认属性
axios.defaults.timeout = 2000 // 超时时间
axios.defaults.headers = { token: 'a15g1eg51d854ge5151eged' } // 请求头
axios.defaults.baseURL = 'http://localhost:5000' // 基础url

// axios 的完整配置项,默认配置项会合并到这里
btn6.click = () => {
axios({
url: `/person`, //请求地址,携带params参数
method: 'get', //请求方法
// params: { a: 1, b: 2 }, // 配置 query 参数
// data: { c: 3, d: 4 }, // 配置请求体参数(json编码)
// data: "e=5&f=6", // 配置请求体参数(urlencoded编码)
// timeout: 2000, // 超时时间
// header: { demo: 123 },// 配置请求头
// responseType: "json", // 配置响应数据的格式(不写默认也是json)
}).then(
(res) => {
// 成功时的回调
console.log('请求成功了', res.data)
},
(err) => {
// 失败时的回调
console.log('请求失败了', err)
}
)
}

axios 的 create 方法

  • axios.create( config)

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

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

  • 03 为什么要设计这个语法?

    • 需求:项目中有部分接口需要的配置与另一部分接口需要的配置不太一样
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const axios2 = axios.create({
timeout: 2000, // 超时时间
headers: { token: 'a15g1eg51d854ge5151eged' }, // 请求头
baseURL: 'http://localhost:5000', // 基础url
})

// 两个配置会进行合并
btn7.click = () => {
axios2({
url: `/person`, //请求地址url
method: 'GET', //请求方法
}).then(
(res) => {
console.log('请求成功了', res.data)
},
(err) => {
console.log('请求失败了', err)
}
)
}

请求拦截器

  • 01 请求拦截器是什么?
    • 在真正发请求前执行的一个回调函数
  • 02 请求拦截器的作用:
    • 对所有的请求做统一的处理: 比如 追加请求头、追加参数、界面 loading 提示等等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 请求拦截器
axios.interceptors.request.use((config) => {
config.headers.token = 'a2g6e1g51dge48g51'
return config
})

btn8.click = () => {
axios({
url: `http://localhost:5000/person`, //请求地址url
method: 'GET', //请求方法
}).then(
(res) => {
console.log('请求成功了', res.data)
},
(err) => {
console.log('请求失败了', err)
}
)
}

响应拦截器

  • 01 响应拦截器是什么?
    • 得到响应之后执行的一组回调函数
  • 02 响应拦截器作用:
    • 若请求成功,对成功的数据进行处理, 若请求失败,对失败进行统一的操作
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
// 响应拦截器
axios.interceptors.response.use(
(res) => {
console.log('响应拦截器成功的回调', res)
// ...
return res.data
},
(err) => {
// axios 将响应状态不是 2 开头的默认为失败
console.log('响应拦截器失败的回调', err)
// ...
return Promise.reject(err)
}
)

btn9.click = () => {
axios({
url: `http://localhost:5000/person`, //请求地址url
method: 'GET', //请求方法
}).then(
(res) => {
console.log('请求成功了', res.data)
},
(err) => {
console.log('请求失败了', err)
}
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 响应拦截器
axios.interceptors.response.use(
(res) => {
console.log('响应拦截器成功的回调', res)
// ...
return res.data
},
(err) => {
// axios 将响应状态不是2开头的默认为失败
console.log('响应拦截器失败的回调', err)
// ...
return new Promise(() => {})
}
)

btn9.click = async () => {
const result = await axios.get('http://localhost:5000/persons')
console.log(result)
}

取消请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const { CancelToken } = axios // CancelToken 能为一次请求"打标识"
let cancel

btn10.click = () => {
axios({
url: `http://localhost:5000/person`,
cancelToken: new CancelToken((c) => {
// c 是一个函数,调用c就可以取消本次请求
cancel = c
}),
}).then(
(res) => {
console.log('请求成功了', res.data)
},
(err) => {
console.log('请求失败了', err)
}
)
}
// 取消请求
btn11.onclick = () => {
cancel('我是取消请求的提示信息,任性取消,就是不要数据了~~')
}
  • 用户主动取消请求,会走 then 中的失败回调
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
const { CancelToken, isCancel } = axios // CancelToken 能为一次请求"打标识"
let cancel

btn10.click = () => {
if (cancel) {
cancel()
} //防止重复请求
axios({
url: `http://localhost:5000/person`,
cancelToken: new CancelToken((c) => {
// c 是一个函数,调用c就可以取消本次请求
cancel = c
}),
}).then(
(res) => {
console.log('请求成功了', res.data)
},
(err) => {
// 用户主动取消请求,也会走失败时的回调
if (isCancel(error)) {
// 如果进入了判断,说明是用户主动取消的请求
console.log('用户取消了请求,原因是:', error.message) // error.message 为取消请求的提示信息
} else {
console.log('请求失败了', err) //err为服务器返回的错误对象
}
}
)
}
// 取消请求
btn11.onclick = () => {
cancel('我是取消请求的提示信息,任性取消,就是不要数据了~~')
}

请求拦截器中取消请求

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
const { CancelToken, isCancel } = axios // CancelToken 能为一次请求"打标识"
let cancel

// 请求拦截器
axios.interceptors.request.use((config) => {
if (cancel) {
cancel('取消了') // 取消请求,避免重复请求
}
config.cancelToken = new CancelToken((c) => {
cancel = c
})
return config
})

// 响应拦截器
axios.interceptors.response.use(
(res) => {
console.log('响应拦截器成功的回调', res)
// ...
return res.data
},
(err) => {
if (isCancel(error)) {
// 如果进入了判断,说明是用于主动取消的请求
console.log('用户取消了请求,原因是:', error.message) //error.message 为取消请求的提示信息
} else {
console.log('请求失败了', err) //err为服务器返回的错误对象
}
return new Promise(() => {})
}
)

// 发起请求
btn10.click = async () => {
const result = await axios.get('http://localhost:5000/persons')
console.log(result)
}

批量发起请求

1
2
3
4
5
6
7
8
9
10
11
12
13
btn.onclick = () => {
axios.all([axios.get('http://localhost:5000/persons1'), axios.get('http://localhost:5000/persons2'), axios.get('http://localhost:5000/persons3')]).then(
(res) => {
// 返回的全部数据会放在一个数组中
// 如果有一个请求有延时,则会等待,当所有数据都回来时,才会一起返回数据
// 底层调用的是 Promise.all() 方法
console.log(res)
},
(err) => {
console.log(err)
}
)
}

扩展

生成 api 文档的工具

  • api-doc