10分钟了解axios
2024-07-06 05:05:44

承接昨天的日志,问到ajax,怎么可能不问axios呢。

正文

这虽然是一次模拟面试,但当模拟真的开始的时候,我开始汗流浃背了。

1
2
3
4
5
面试官:能详细说说axios吗?

我:项目中常用的一个工具库,封装接口请求的工具方法。

面试官:很高兴面试您,如果后续有结果了,我们会通知您的。

虽然知道今年很卷,但是比想象中要卷的多。

本节为 Axios 常规使用,更多方法请看Axios中文文档Axios中文文档(官方)、开源API库:BootCDN

Axios概念

Axios 是一个基于 promise 的网络请求库,作用于 node.js 和浏览器中,它是 isomorphic 的 (即同一套代码可以运行在浏览器和 node.js 中)。

在服务端它使用原生 node.js http 模块,而在客户端 (浏览端) 则使用 XMLHttpRequest

  • Axios 本质上是对原生 XMLHttpRequest 的封装,只不过它是 Promise 的实现版本,符合最新的 ES6 规范

Promise教程请参考:juejin.cn/post/732199…

主要特点:

  • 从浏览器创建 XMLHttpRequests、从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 超时处理
  • 自动将请求体序列化
  • 自动转换 JSON 数据

使用方式

安装

  • 使用 npm
1
npm install axios
  • 使用 CDN
1
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

基本使用

可以向 axios 传递相关配置来创建请求

  • axios(config)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 发起一个get请求, 参数名和值会自动拼接到url
axios({
method: 'get',
url: '/user/12345',
params: {
firstName: 'Fred',
lastName: 'Flintstone'
}
})

// 发起一个post请求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
})

常用请求方法:

请求方法 操作
GET 获取数据
POST 提交数据
PUT 修改数据(全部)
DELETE 删除数据
PATCH 修改数据(部分)

为方便起见,为所有支持的请求方法提供了别名:

无 data 属性:

  • axios.request(config)
  • axios.get(url[, config])
  • axios.delete(url[, config])
  • axios.head(url[, config])
  • axios.options(url[, config])

有 data 属性:

  • axios.post(url[, data[, config]])
  • axios.put(url[, data[, config]])
  • axios.patch(url[, data[, config]])
  • axios.postForm(url[, data[, config]])
  • axios.putForm(url[, data[, config]])
  • axios.patchForm(url[, data[, config]])

别名中的data属性无需显式给出,只需传入一个对象即可

下面是使用方法别名的示例:

  • GET 请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
axios.get('/user', {
params: {
ID: 12345
}
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})

// 支持async/await用法
async function getUser() {
try {
const response = await axios.get('/user?ID=12345')
console.log(response)
} catch (error) {
console.error(error)
}
}
  • POST 请求
1
2
3
4
5
6
7
8
9
10
11
12
js复制代码// data属性直接为一个对象, 无需显式给出
const {data} = await axios.post('https://httpbin.org/post', {
firstName: 'Fred',
lastName: 'Flintstone',
orders: [1, 2, 3],
photo: document.querySelector('#fileInput').files
}, {
headers: {
'Content-Type': 'multipart/form-data'
}
}
)

取消请求

Axios 支持以 fetch API 方式—— AbortController 取消请求

1
2
3
4
5
6
7
8
9
js复制代码const controller = new AbortController();

axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// 取消请求
controller.abort()

请求配置

以下是创建请求时可以用的配置选项只有 url 是必需的。如果没有指定 method,请求将默认使用 GET 方法

配置源于官网,已将常用配置移到最前

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
{
// 请求的服务器 URL
url: '/user',

// 创建请求时使用的方法
method: 'get', // 默认值

// baseURL 自动加在url前,除非url是一个绝对 URL
baseURL: 'https://some-domain.com/api/',

// 自定义请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},

// params 是与请求一起发送的 URL 参数, 与 get 方法搭配使用
params: {
ID: 12345
},

// data 是作为请求体被发送的数据 (PUT、POST、DELETE、PATCH)
// 在没有设置 `transformRequest` 时,则必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属: FormData, File, Blob
// - Node 专属: Stream, Buffer
data: {
firstName: 'Fred'
},

// 指定请求超时的毫秒数, 超时则请求会被中断
timeout: 1000, // 默认值是 0 (永不超时)

// responseType 表示浏览器将要响应的数据类型
// 包括: 'arraybuffer', 'document', 'json', 'text', 'stream'
// 浏览器专属:'blob'
responseType: 'json', // 默认值

// auth 示应该使用 HTTP 基础验证,并提供凭据
// 这将设置一个 Authorization ,覆写掉现有的任意使用 headers 置的自定义 Authorization
auth: {
username: 'janedoe',
password: 's00pers3cret'
},

// `transformRequest` 允许在向服务器发送前,修改请求数据
// 它只能用于 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData,或 Stream
// 你可以修改请求头。
transformRequest: [function (data, headers) {
// 对发送的 data 进行任意转换处理
return data;
}],

// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [function (data) {
// 对接收的 data 进行任意转换处理
return data;
}],

// `paramsSerializer`是可选方法,主要用于序列化`params`
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function (params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},

// `withCredentials` 表示跨域请求时是否需要使用凭证
withCredentials: false, // default

// `adapter` 允许自定义处理请求,这使测试更加容易。
// 返回一个 promise 并提供一个有效的响应 (参见 lib/adapters/README.md)。
adapter: function (config) {
/* ... */
},

// `responseEncoding` 表示用于解码响应的编码 (Node.js 专属)
// 注意:忽略 `responseType` 的值为 'stream',或者是客户端请求
// Note: Ignored for `responseType` of 'stream' or client-side requests
responseEncoding: 'utf8', // 默认值

// `xsrfCookieName` 是 xsrf token 的值,被用作 cookie 的名称
xsrfCookieName: 'XSRF-TOKEN', // 默认值

// `xsrfHeaderName` 是带有 xsrf token 值的http 请求头名称
xsrfHeaderName: 'X-XSRF-TOKEN', // 默认值

// `onUploadProgress` 允许为上传处理进度事件 (浏览器专属)
onUploadProgress: function (progressEvent) {
// 处理原生进度事件
},

// `onDownloadProgress` 允许为下载处理进度事件 (浏览器专属)
onDownloadProgress: function (progressEvent) {
// 处理原生进度事件
},

// `maxContentLength` 定义了node.js中允许的HTTP响应内容的最大字节数
maxContentLength: 2000,

// `maxBodyLength`(仅Node)定义允许的http请求内容的最大字节数
maxBodyLength: 2000,

// `validateStatus` 定义了对于给定的 HTTP状态码是 resolve 还是 reject promise。
// 如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),
// 则promise 将会 resolved,否则是 rejected。
validateStatus: function (status) {
return status >= 200 && status < 300; // 默认值
},

// `maxRedirects` 定义了在node.js中要遵循的最大重定向数。
// 如果设置为0,则不会进行重定向
maxRedirects: 5, // 默认值

// `socketPath` 定义了在node.js中使用的UNIX套接字。
// e.g. '/var/run/docker.sock' 发送请求到 docker 守护进程。
// 只能指定 `socketPath` 或 `proxy` 。
// 若都指定,这使用 `socketPath` 。
socketPath: null, // default

// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理
// `keepAlive` 默认没有启用
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),

// `proxy` 定义了代理服务器的主机名,端口和协议。
// 您可以使用常规的`http_proxy` 和 `https_proxy` 环境变量。
// 使用 `false` 可以禁用代理功能,同时环境变量也会被忽略。
// `auth`表示应使用HTTP Basic auth连接到代理,并且提供凭据。
// 这将设置一个 `Proxy-Authorization` 请求头,它会覆盖 `headers` 中已存在的自定义 `Proxy-Authorization` 请求头。
// 如果代理服务器使用 HTTPS,则必须设置 protocol 为`https`
proxy: {
protocol: 'https',
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
},

// see https://axios-http.com/zh/docs/cancellation
cancelToken: new CancelToken(function (cancel) {
}),

// `decompress` indicates whether or not the response body should be decompressed
// automatically. If set to `true` will also remove the 'content-encoding' header
// from the responses objects of all decompressed responses
// - Node only (XHR cannot turn off decompression)
decompress: true // 默认值
}

响应结构

一个请求的响应包含以下结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
// 由服务器提供的响应
data: {},

// HTTP 状态码
status: 200,

// HTTP 状态信息
statusText: 'OK',

// 服务器响应头, 所有的 header 名称都是小写, 而且可以使用方括号语法访问
// 例如: response.headers['content-type']
headers: {},

// axios 请求的配置信息
config: {},

// 生成此响应的请求
// 在node.js中它是最后一个ClientRequest实例 (in redirects),
// 在浏览器中则是 XMLHttpRequest 实例
request: {}
}

Axios默认配置

常规开源项目中的常见封装方式。

全局默认配置

1
2
3
axios.defaults.baseURL = 'https://api.example.com'
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'

自定义实例

可以使用自定义配置新建一个实例:axios.create([config])

1
2
3
4
5
6
7
// 创建实例时配置默认值
const instance = axios.create({
baseURL: 'https://api.example.com'
})

// 创建实例后修改默认值
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN

配置优先级

配置将会按优先级进行合并

  • 优先级:lib/defaults.js默认值 < 实例 defaults 属性 < 请求 config 参数
1
2
3
4
5
6
7
8
9
10
11
js复制代码// 使用库提供的默认配置创建实例
// 此时超时配置的默认值是 0
const instance = axios.create()

// 重写库的超时默认值
instance.defaults.timeout = 2500

// 重写此请求的超时时间,因为该请求需要很长时间
instance.get('/longRequest', {
timeout: 5000
})

拦截器

在请求或响应被 then 或 catch 处理前拦截它们

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
js复制代码// 请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})

// 响应拦截器
axios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数
// 对响应数据做点什么
return response
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数
// 对响应错误做点什么
return Promise.reject(error)
})

拦截器完整使用示例:

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
js复制代码// 创建一个单独的axios实例
const instance = axios.create({
baseURL: 'https://xxx.xxx.xxx',
timeout: 6000
})

// 请求拦截器
instance.interceptors.request.use(
(config) => {
const store = userStore()
if (store.user?.token) {
config.headers.authorization = `Bearer ${store.user?.token}`
}
return config
},
(err) => Promise.reject(err)
)

// 响应拦截器
// 数据脱壳、业务成功、业务失败、401 token失效的处理
instance.interceptors.response.use(
(res) => {
// 下面判断用户请求的业务成功
if (res.data?.code === 10000) {
// 数据脱壳
return res.data
} else {
// 业务失败, 提示错误
showToast(res.data?.message || '请求失败')
return Promise.reject(res)
}
},
(err) => {
// 下面这里的函数是请求失败,http状态码是 4xx 5xx
if (err.response?.status === 401) {
// 处理401错误
const store = userStore()
store.delUser()
router.push('/login')
}
return Promise.reject(err)
}
)

export default instance

如果需要移除拦截器,可以这样:

1
2
const myInterceptor = axios.interceptors.request.use(function () {/*...*/})
axios.interceptors.request.eject(myInterceptor)

结语

面向面试开发的感觉,这些东西平日用的太顺手,整理出来甚至也不算细究,只是调用别人的工具方法。

但是在面试时候问出来,真是有一种。。。。无趣的感觉。

累了,这次单纯是为了面试整理了一下知识点,后续大概不会持续关注这种工具方法。

参考

一文熟悉Ajax