源码目录结构

源码分析
axios与Axios的关系?
- 从语法上来说: axios不是Axios的实例
- 从功能上来说: axios是Axios的实例
- axios是Axios.prototype.request函数bind()返回的函数
- axios作为对象有Axios原型对象上的所有方法, 有Axios对象上所有属性
instance与axios的区别?
- 相同:
(1) 都是一个能发任意请求的函数: request(config)
(2) 都有发特定请求的各种方法: get()/post()/put()/delete()
(3) 都有默认配置和拦截器的属性: defaults/interceptors - 不同:
(1) 默认配置很可能不一样
(2) instance没有axios后面添加的一些方法: create()/CancelToken()/all()
axios运行的整体流程?

- 整体流程:
request(config) ==> dispatchRequest(config) ==> xhrAdapter(config) - request(config):
将请求拦截器 / dispatchRequest() / 响应拦截器 通过promise链串连起来, 返回promise - dispatchRequest(config):
转换请求数据 ===> 调用xhrAdapter()发请求 ===> 请求返回后转换响应数据. 返回promise - xhrAdapter(config):
创建XHR对象, 根据config进行相应设置, 发送特定请求, 并接收响应数据, 返回promise
axios的请求/响应拦截器是什么?

-
请求拦截器:
在真正发送请求前执行的回调函数
可以对请求进行检查或配置进行特定处理
成功的回调函数, 传递的默认是config(也必须是)
失败的回调函数, 传递的默认是error
-
响应拦截器
在请求得到响应后执行的回调函数
可以对响应数据进行特定处理
成功的回调函数, 传递的默认是response
失败的回调函数, 传递的默认是error
axios的请求/响应数据转换器是什么?
- 请求转换器: 对请求头和请求体数据进行特定处理的函数
javascript
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
return JSON.stringify(data);
}
- 响应转换器: 将响应体json字符串解析为js对象或数组的函数
javascript
response.data = JSON.parse(response.data)
response的整体结构
javascript
{
data,
status,
statusText,
headers,
config,
request
}
error的整体结构
javascript
{
message,
response,
request,
}
如何取消未完成的请求?
- 当配置了cancelToken对象时, 保存cancel函数
(1) 创建一个用于将来中断请求的cancelPromise
(2) 并定义了一个用于取消请求的cancel函数
(3) 将cancel函数传递出来 - 调用cancel()取消请求
(1) 执行cacel函数, 传入错误信息message
(2) 内部会让cancelPromise变为成功, 且成功的值为一个Cancel对象
(3) 在cancelPromise的成功回调中中断请求, 并让发请求的proimse失败, 失败的reason为Cancel对象
Axios二次封装
功能点
- 统一进行请求配置: 基础路径/超时时间等
- 请求过程中loading提示
- 请求可能需要携带token数据
- 请求成功的value不再是response, 而是response.data
- 请求失败/出错统一进行处理, 每个请求可以不用单独处理
编码实现与测试
javascript
<!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>