Axios 是什么
简介
Axios 是一个基于 Promise 的 HTTP 客户端,可以在浏览器和 Node.js 环境中使用。简化了前端发送 HTTP 请求的流程,提供了拦截器、自动解析 JSON 等强大功能。
它就是一个专门用来发送 HTTP 请求的工具库,相比浏览器原生的
XMLHttpRequest 或者 Fetch
API,它有更简洁的语法、更强大的功能(比如拦截器、请求取消、自动转换 JSON
数据等),因此成为了前后端分离项目中对接后端接口的首选工具。
它的核心特点:
- 支持 Promise API,便于异步操作的处理(async/await 语法)。
- 拦截请求和响应(比如请求前添加 token、响应后统一处理错误)。
- 自动转换请求和响应数据(比如自动将 JSON 字符串转为 JavaScript 对象)。
- 取消请求。
- 客户端支持防御 XSRF(跨站请求伪造)。
在前后端分离架构中,前端(如 Vue/React/Angular)通过 Axios 向后端(如 Java/SpringBoot、Node.js/Express、Python/Django)的接口发送 HTTP 请求,后端处理请求后返回数据,前端再根据返回的数据渲染页面,这就是核心的对接流程。
那么 Vue 中也是一样,前端通过 Axios 发送 GET/POST
等请求到后端接口,后端处理请求后返回数据,前端通过
then/async/await 接收数据并处理,通过
catch 处理错误。
如何使用Axios
安装它和安其它包一样:npm install axios
1 | # npm 安装 |
安装完成后,就可以在组件或 js 文件中引入并发送请求了。以下是最基础的 GET、POST 请求示例:
1 | // 引入 Axios |
上述仅为演示,实际上,没有人在项目中真这么写,因此,我们会对 Axios 进行二次封装,抽离出公共的配置和逻辑。
我们会创建一个 Axios 实例并配置(如
src/utils/request.js)
1 | import axios from 'axios'; |
然后在需要的时候使用它,一般用在封装接口请求的时候(如
src/api/user.js),把所有和用户相关的接口抽离到一个文件中,便于维护:
1 | // 引入封装后的 Axios 实例 |
然后才会在 Vue组件中使用封装后的接口
1 | import { getUserList, addUser } from '@/api/user'; |
而且在开发环境中,前端项目通常运行在
http://localhost:3000,后端接口运行在
http://localhost:8080,由于浏览器的同源策略,会出现跨域问题。此时需要配置代理来解决,在
vue.config.js 中配置代理:
1 | module.exports = { |
这样,前端发送的 /api/users 请求会被代理到
http://localhost:8080/api/users,从而解决跨域问题。
这些都是预览,下面会细说
Axios API
基本API及其别名
Axios 内置了很多基本的 API,可以向 axios
传递相关配置来创建请求,但是我们基本上都会封装成实例来用,可以这样进行分类:
- 请求方法别名 API:最常用的
axios.get()、axios.post()等,是对核心方法的封装。 - 核心请求 API:
axios(config)和axios(url, config),是所有请求的底层实现。 - 实例相关 API:
axios.create()创建自定义实例,以及实例上的请求方法、拦截器等。 - 辅助 API:处理请求取消、并发请求的工具 API(如
axios.all()、axios.CancelToken)。
核心请求 API,是 Axios 最基础的 API,所有其他请求方法都是基于它封装的,灵活性最高。
axios(config),例如
1 | // 发起一个post请求 |
它有两种的调用形式
1 | import axios from 'axios'; |
配置对象,也就是axios(config)中的config,是
Axios API 的核心
| 配置项 | 类型 | 说明 |
|---|---|---|
url |
String | 请求的服务器 URL(必填) |
method |
String | HTTP 请求方法,可选值:get/post/put/delete/head/options 等(默认 get) |
params |
Object/URLSearchParams | GET 请求的参数,会被拼接到 URL 后(如
/api/users?id=1) |
data |
Object/FormData/String | 非 GET 方法的请求体数据,会被发送到后端 |
headers |
Object | 自定义请求头(如 token、Content-Type) |
timeout |
Number | 请求超时时间(毫秒),超过则中断请求(默认无超时) |
baseURL |
String | 基础 URL,所有请求的 URL 都会拼接这个前缀(如
baseURL: '/api',则 url: '/users' 最终是
/api/users) |
responseType |
String | 期望的响应数据类型,可选值:json/blob/document/arraybuffer/text(默认 json,Axios 会自动解析 JSON) |
withCredentials |
Boolean | 是否携带跨域 cookies(解决跨域身份验证问题,默认 false) |
paramsSerializer |
Function | 自定义 params 序列化规则(比如处理数组、特殊字符) |
为了简化开发,Axios 对常用的 HTTP 方法封装了别名
API,不需要手动写 method
等的配置,代码更简洁。
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
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]])
在使用别名方法时,
url、method、data
这些属性都不必在配置中指定。
别名方法中,GET/DELETE/HEAD/OPTIONS 这类方法没有
data 参数(因为 HTTP
规范中这些方法的请求体是可选的,后端通常也不处理),参数只能放在
params 或 URL 中;而 POST/PUT/PATCH 可以传
data 作为请求体。
辅助API
并发请求 API:
axios.all()+axios.spread()用于同时发送多个请求,等待所有请求都完成后再处理结果(比如同时获取用户信息和订单信息)。
1
2
3
4
5
6
7
8
9
10
11
12// 定义两个请求
const request1 = axios.get('/api/user/1');
const request2 = axios.get('/api/order/1');
// 并发请求:等待两个请求都完成
axios.all([request1, request2])
.then(axios.spread((res1, res2) => {
// res1 是 request1 的结果,res2 是 request2 的结果
console.log('用户信息:', res1.data);
console.log('订单信息:', res2.data);
}))
.catch(err => console.error(err));在现代 JavaScript 中,
axios.all()可以用Promise.all()替代,axios.spread()可以用解构赋值替代1
2
3
4Promise.all([request1, request2])
.then(([res1, res2]) => {
console.log(res1.data, res2.data);
});取消请求 API:
AbortController/CancelToken用于中断正在发送的请求(比如用户快速切换标签、输入搜索关键词时取消前一次请求)。
注意:Axios v0.22.0 及以上版本推荐使用浏览器原生的
AbortController,CancelToken已被标记为过时。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// 方法1:使用 AbortController(推荐)
const controller = new AbortController();
// 发送请求时关联 signal
axios.get('/api/users', {
signal: controller.signal // 绑定取消信号
})
.then(res => console.log(res))
.catch(err => {
// 捕获取消请求的错误
if (axios.isCancel(err)) {
console.log('请求被取消:', err.message);
} else {
console.error('请求失败:', err);
}
});
// 取消请求(可传入自定义提示信息)
controller.abort('用户主动取消请求');
// 方法2:使用 CancelToken(旧版)
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/api/users', {
cancelToken: source.token
})
.catch(err => {
if (axios.isCancel(err)) {
console.log('请求被取消:', err.message);
}
});
// 取消请求
source.cancel('用户主动取消请求');axios.isCancel(error):判断错误是否是取消请求导致的(上面示例已用)。axios.defaults:设置全局默认配置(比如全局 baseURL、timeout):
Axios 实例
创建一个实例
一般情况下,很少直接调用上面的api,使用Axios我们都自定义实例,可以使用自定义配置新建一个实例。这样可以为不同的后端服务配置不同的基础 URL、拦截器等,避免全局配置冲突。
axios.create([config])
它接收一个配置对象作为参数,返回一个新的 Axios 实例
1 | // 创建一个针对用户服务的 Axios 实例 |
创建的实例和全局的 axios
对象功能完全一致,拥有相同的 API:
- 别名方法:
get()、post()、put()、delete()等。 - 拦截器:
interceptors.request、interceptors.response。 - 配置项:可以修改实例的默认配置。
使用Axios实例
实例的请求方法和全局 axios 一致
实例可以直接调用所有请求别名方法,用法和全局 axios
完全相同,只是会使用实例的默认配置
1 | // 使用 userService 实例发送请求 |
每个实例可以配置独立的请求拦截器和响应拦截器,实现不同服务的逻辑隔离
请求拦截器,请求发送前处理
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// 为 userService 实例添加请求拦截器(添加用户 token)
userService.interceptors.request.use(
(config) => {
// 从本地存储获取用户 token,添加到请求头
const userToken = localStorage.getItem('userToken');
if (userToken) {
config.headers['Authorization'] = `Bearer ${userToken}`;
}
return config; // 必须返回配置,否则请求会中断
},
(error) => {
// 处理请求配置错误(比如参数错误)
return Promise.reject(error);
}
);
// 为 orderService 实例添加请求拦截器(添加订单 token + 加载动画)
orderService.interceptors.request.use(
(config) => {
const orderToken = localStorage.getItem('orderToken');
if (orderToken) {
config.headers['Order-Token'] = orderToken;
}
// 显示加载动画(比如 Element UI 的 Loading)
// loadingInstance = ElLoading.service({ fullscreen: true });
return config;
},
(error) => {
// 关闭加载动画
// loadingInstance.close();
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// 为 userService 实例添加响应拦截器(处理用户服务的错误)
userService.interceptors.response.use(
(response) => {
// 成功响应:只返回后端的核心数据(简化数据处理)
return response.data;
},
(error) => {
// 失败响应:统一处理错误
if (error.response?.status === 401) {
// 用户 token 过期,跳转到登录页
window.location.href = '/user/login';
alert('用户登录已过期,请重新登录');
} else if (error.response?.status === 403) {
alert('您没有访问用户数据的权限');
}
return Promise.reject(error);
}
);
// 为 orderService 实例添加响应拦截器(处理订单服务的错误 + 关闭加载动画)
orderService.interceptors.response.use(
(response) => {
// 关闭加载动画
// loadingInstance.close();
return response.data;
},
(error) => {
// 关闭加载动画
// loadingInstance.close();
if (error.response?.status === 401) {
// 订单 token 过期,跳转到订单授权页
window.location.href = '/order/auth';
alert('订单授权已过期,请重新授权');
} else if (error.response?.status === 500) {
alert('订单服务异常,请稍后重试');
}
return Promise.reject(error);
}
);
拦截器可以动态添加和移除,如果需要动态移除某个拦截器(比如特定场景下不需要拦截逻辑),可以保存拦截器的引用,然后调用
eject 方法:
1 | // 保存请求拦截器的引用 |
创建实例后,还可以通过 实例.defaults
修改实例的默认配置,优先级低于创建时的配置,但高于单个请求的配置
1 | // 修改 userService 实例的默认超时时间为 8 秒 |
这里涉及到配置优先级的问题,Axios 的配置可以在全局、实例、单个请求三个层面设置,它们的优先级是:
单个请求的配置 > 实例的默认配置 > 全局 axios 的默认配置
全局axios的默认值如下
1 | axios.defaults.baseURL = 'https://api.example.com'; |
在实际项目中,我们会把 Axios 实例的创建、拦截器配置抽离成独立的工具文件,然后再封装接口请求,让代码更规范、易维护
请求配置
下面的官网中官方文档的描述
1 | { |
首先明确两个基础规则
- 必填项只有
url:所有配置中,只有url是必须传的,其他配置都是可选的。 - 默认请求方法是 GET:如果不配置
method,请求会默认使用 GET 方法。
基础路径与方法,决定了请求的地址和HTTP 方法,是每个请求的基础
| 配置项 | 类型 | 说明 | 示例 |
|---|---|---|---|
url |
String | 必需,请求的服务器 URL(可以是相对路径或绝对路径) | url: '/user' 或
url: 'https://api.example.com/user' |
method |
String | 可选,HTTP 请求方法,支持
get/post/put/delete/patch/head/options |
method: 'post'(默认是 get) |
baseURL |
String | 可选,自动拼接到 url 前面(除非 url
是绝对路径),用于统一设置接口前缀 |
baseURL: 'https://api.example.com/api',此时
url: '/user' 最终地址是
https://api.example.com/api/user |
这部分在开发的时候,实际上我们都会在创建 Axios 实例时设置
baseURL,避免每个请求都写完整的域名
1 | const service = axios.create({ |
数据处理,这类配置允许你在发送请求前修改请求数据,或接收响应后修改响应数据,常用于数据加密、格式化等场景。
| 配置项 | 类型 | 说明 | 注意事项 |
|---|---|---|---|
transformRequest |
Array<Function> |
可选,发送请求前修改请求数据,仅适用于 PUT/POST/PATCH
方法 |
最后一个函数必须返回字符串、Buffer、FormData 等可发送的格式;可以修改请求头 |
transformResponse |
Array<Function> |
可选,接收响应后、传递给 then/catch 前修改响应数据 |
可以对后端返回的数据进行预处理,比如解密、格式化 |
例如,数据请求加密就可以这样写
1 | axios({ |
参数与请求体相关配置如下,这类配置用于传递URL 参数(GET)和请求体数据(POST/PUT),是前后端数据交互的核心。
| 配置项 | 类型 | 说明 | 示例 |
|---|---|---|---|
headers |
Object | 可选,自定义请求头,比如设置 Content-Type、token | headers: { 'Authorization': 'Bearer token123', 'Content-Type': 'multipart/form-data' } |
params |
Object/URLSearchParams | 可选,GET 请求的 URL 参数,会自动拼接到 URL 后 | params: { id: 1, page: 1 } → URL 变为
/user?id=1&page=1 |
paramsSerializer |
Object/Function | 可选,自定义 params 的序列化规则,解决默认序列化的问题(比如数组、特殊字符) | 处理数组参数:默认是 arr[]=1&arr[]=2,可以改为
arr=1&arr=2 |
data |
Object/String/FormData/Blob | 可选,请求体数据,仅适用于 PUT/POST/DELETE/PATCH |
可以是 JSON 对象、表单数据、文件流等 |
注意,Axios 默认对数组的序列化是
arr[]=1&arr[]=2,但有些后端框架不支持这种格式,需要用
paramsSerializer 自定义。
1 | axios({ |
超时与跨域,这类配置用于设置请求的超时时间、跨域是否携带凭证等,解决请求的基础问题。
| 配置项 | 类型 | 说明 | 示例 |
|---|---|---|---|
timeout |
Number | 可选,请求超时时间(毫秒),超过则中断请求 | timeout: 5000(5 秒超时,默认 0 表示永不超时) |
withCredentials |
Boolean | 可选,跨域请求时是否携带 cookies / 认证信息 | withCredentials: true(解决跨域身份验证问题,需要后端配合设置
CORS) |
例如,跨域携带 cookies:
1 | axios({ |
此时后端需要设置 Access-Control-Allow-Origin
为前端域名,且
Access-Control-Allow-Credentials: true,否则浏览器会阻止。
响应处理,这类配置决定了 Axios 如何解析响应数据、判断请求是否成功,以及限制响应数据的大小。
| 配置项 | 类型 | 说明 | 示例 |
|---|---|---|---|
responseType |
String | 可选,期望的响应数据类型,默认 json |
可选值:json(默认,自动解析
JSON)、blob(文件流)、text(纯文本)、arraybuffer(二进制数据) |
responseEncoding |
String | 可选,解码响应的编码(仅 Node.js 专属) | responseEncoding: 'utf8'(默认) |
maxContentLength |
Number | 可选,Node.js 中允许的响应内容最大字节数 | maxContentLength: 1024 * 1024(1MB) |
maxBodyLength |
Number | 可选,Node.js 中允许的请求内容最大字节数 | maxBodyLength: 1024 * 1024(1MB) |
validateStatus |
Function | 可选,定义 HTTP 状态码是否视为成功(resolve promise) | 默认是
status >= 200 && status < 300,可以自定义(比如允许
304 状态码) |
例如,下载文件(responseType: ‘blob’)
1 | axios({ |
进度与安全,这类配置用于处理上传 / 下载的进度事件,以及防御跨站请求伪造(CSRF)。
| 配置项 | 类型 | 说明 | 实战场景 |
|---|---|---|---|
onUploadProgress |
Function | 可选,上传进度事件(仅浏览器专属) | 显示文件上传的进度条 |
onDownloadProgress |
Function | 可选,下载进度事件(仅浏览器专属) | 显示文件下载的进度条 |
xsrfCookieName |
String | 可选,CSRF token 的 cookie 名称,默认 XSRF-TOKEN |
防御 CSRF 攻击,Axios 会自动从 cookie 中读取该值,添加到请求头 |
xsrfHeaderName |
String | 可选,携带 CSRF token 的请求头名称,默认
X-XSRF-TOKEN |
例如,文件上传进度条
1 | // 选择文件的 input 元素 |
代理、取消请求、重定向等其他配置
| 配置项 | 类型 | 说明 | 实战场景 |
|---|---|---|---|
auth |
Object | 可选,HTTP 基础认证(Basic Auth) | 访问需要用户名密码的接口,Axios 会自动添加
Authorization 头 |
cancelToken |
CancelToken/AbortSignal | 可选,取消请求的令牌(新版用 AbortSignal,旧版用 CancelToken) | 取消正在发送的请求(比如用户快速切换标签) |
proxy |
Object/Boolean | 可选,代理服务器配置(仅 Node.js 专属) | Node.js 中通过代理发送请求,比如访问外网接口 |
maxRedirects |
Number | 可选,Node.js 中允许的最大重定向数,默认 5 | 限制请求的重定向次数,避免无限重定向 |
socketPath |
String | 可选,Node.js 中使用的 UNIX 套接字 | 连接 Docker 守护进程等本地服务 |
httpAgent/httpsAgent |
Object | 可选,Node.js 中自定义 HTTP/HTTPS 代理 | 设置长连接(keepAlive)等选项 |
decompress |
Boolean | 可选,是否自动解压响应体(仅 Node.js 专属) | 默认 true,关闭则不解压 |
adapter |
Function | 可选,自定义请求适配器 | 测试时模拟请求,或自定义请求处理逻辑 |
响应结构
当 Axios 发送请求并成功收到后端的响应后,会返回一个响应对象(Response),这个对象包含了后端返回的所有信息,以及请求的配置和底层请求对象。
首先:
- 响应对象是
then回调的唯一参数(请求成功时)。 - 所有响应头的名称都会被自动转为小写(比如
Content-Type变成content-type)。 - 即使在响应拦截器中修改了响应数据,最终拿到的对象依然保留这些核心属性(或被拦截器简化)。
而且,一个请求的响应包含以下信息。
1 | { |
data:服务器返回的核心数据类型:任意类型,因为是后端接口返回的实际数据,取决于
responseType配置如果
responseType是默认的json,Axios 会自动将后端返回的 JSON 字符串解析为 JavaScript 对象 / 数组。1
2
3
4
5
6
7
8axios.get('/api/user/1')
.then(response => {
// 后端返回的数据:{ "code": 200, "data": { "name": "张三", "age": 20 }, "msg": "成功" }
console.log(response.data); // 解析后的对象:{ code: 200, data: { name: '张三', age: 20 }, msg: '成功' }
// 提取用户信息
const userInfo = response.data.data;
console.log(userInfo.name); // 张三
});
status:HTTP 状态码类型:Number。
含义:服务器返回的 HTTP 状态码,代表请求的处理结果
例如,根据状态码做特殊处理
1
2
3
4
5
6
7
8
9axios.post('/api/user', { name: '李四' })
.then(response => {
if (response.status === 201) {
console.log('用户新增成功(HTTP 201)');
} else if (response.status === 200) {
console.log('用户新增成功(HTTP 200)');
}
console.log(response.data);
});
statusText:HTTP 状态信息- 类型:String。
- 含义:服务器返回的 HTTP 状态文本,与
status一一对应(如 200 对应OK,404 对应Not Found)。 - 注意:状态文本是 HTTP 协议规定的
headers:服务器响应头- 类型:Object。
- 含义:服务器返回的响应头信息,所有头名称都会被转为小写。
- 常用响应头
content-type:响应数据的类型(如application/json、text/html、multipart/form-data)。content-length:响应数据的字节数。cache-control:缓存控制策略(如no-cache、max-age=3600)。authorization:认证令牌(少数后端会在响应头返回 token)。
1
2
3
4
5
6
7
8
9axios.get('/api/user/1')
.then(response => {
// 获取响应数据的类型
console.log(response.headers['content-type']); // application/json; charset=utf-8
// 获取缓存控制策略
console.log(response.headers['cache-control']); // no-cache
// 注意:头名称是小写,不能写 Content-Type
console.log(response.headers['Content-Type']); // undefined
});- 注意,跨域请求中,在浏览器中,跨域请求时只能获取简单响应头(如
content-type、cache-control),如果需要获取自定义响应头(如x-token),后端需要设置Access-Control-Expose-Headers头,指定允许前端访问的自定义头。
config:请求的配置对象类型:Object。
含义:发送请求时使用的所有配置信息(包括默认配置、实例配置、单个请求配置)。
1
2
3
4
5
6
7
8
9
10axios.get('/api/user/1', {
params: { id: 1 },
timeout: 5000
})
.then(response => {
console.log(response.config.url); // /api/user/1
console.log(response.config.method); // get
console.log(response.config.params); // { id: 1 }
console.log(response.config.timeout); // 5000
});
request:生成响应的请求对象- 类型
- 浏览器环境:
XMLHttpRequest实例(原生 AJAX 对象)。 - Node.js 环境:
ClientRequest实例(Node.js 内置的 HTTP 请求对象)。
- 浏览器环境:
- 含义:底层的请求对象,通常在开发中不需要使用,主要用于调试或特殊场景(比如获取请求的响应时间)。
- 类型
在实际中,我们通常会在响应拦截器中对响应对象进行处理(比如只返回
data,简化后续代码),这是对响应对象最常见的实战用法。
例如,简化响应数据,只返回 data
1 | import axios from 'axios'; |
当请求失败时(比如网络错误、HTTP 状态码非
2xx),错误对象中也会包含响应对象(error.response),这是处理错误的关键。
1 | service.interceptors.response.use( |
当 responseType 配置为非 json 时(如
blob、text、arraybuffer),data
属性的类型会对应变化,这是处理文件下载、纯文本响应的关键。
例如,处理文件下载,也就是responseType: 'blob'
1 | // 下载 Excel 文件 |
错误处理
首先要明确:Axios 在请求过程中产生的错误,主要分为三大类
| 错误类型 | 产生原因 | 特征(如何判断) |
|---|---|---|
| 服务器响应错误 | 请求发送成功,服务器返回了状态码,但状态码不在 2xx
范围内(默认规则) |
error.response 存在(非 undefined) |
| 无响应错误 | 请求发送成功,但没有收到服务器的响应(如网络断开、请求超时、服务器宕机) | error.request 存在,error.response
不存在 |
| 请求配置 / 代码错误 | 发送请求前就出现了错误(如 URL 写错、数据格式错误、Axios 配置错误) | error.message 存在,error.request
不存在 |
除此之外,还有一个兜底的属性:error.config,它在所有错误类型中都存在,代表发送请求时的配置对象,可用于调试或重新发起请求。
服务器响应错误(error.response
存在)
这是最常见的错误类型,比如后端返回
401(未授权)、404(资源不存在)、500(服务器内部错误)等。
此时,
- 请求已经到达服务器,服务器处理后返回了 HTTP 状态码,但状态码不在
Axios 默认的成功范围内(
200 <= status < 300)。 error.response包含完整的响应信息:data(后端返回的错误数据)、status(状态码)、headers(响应头)。
1 | axios.get('/user/12345') |
第二类:无响应错误(error.request
存在)
这类错误是网络层面的问题,请求发出去了,但服务器没有任何回应。
这种情况一般就是网络断开、请求超时(timeout
配置触发)、服务器宕机、跨域配置错误导致浏览器拦截响应。
1 | axios.get('/user/12345') |
请求超时也属于这类错误!比如配置了
timeout: 5000,如果请求超过 5 秒还没收到响应,就会触发
error.request。
请求配置 /
代码错误(error.message 存在)
这类错误是在发送请求之前就发生的,属于前端代码或配置的问题。
此时错误信息会被存储在 error.message
中,描述错误的具体原因
1 | axios.get('/user/12345') |
无论哪种错误,error.config
都存在,它是发送请求时的完整配置对象(包含
URL、method、params、data、timeout 等)。
自定义错误判定规则:validateStatus
Axios 默认的规则是:只有状态码在
200 <= status < 300 范围内,才会触发
then;否则触发 catch。但我们可以通过
validateStatus
配置项自定义这个规则,决定哪些状态码算 “成功”,哪些算
“错误”。
validateStatus 的基本用法
validateStatus 是一个函数,接收
status(HTTP 状态码)作为参数,返回一个布尔值:
- 返回
true:状态码被视为成功,触发then。 - 返回
false:状态码被视为错误,触发catch。
1 | axios.get('/user/12345', { |
304 状态码表示
“资源未修改,使用缓存”,默认属于成功,但如果需要特殊处理,可以通过
validateStatus 配置:
1 | axios.get('/user/12345', { |
神秘小知识,这样写,全部状态码都触发 then
1 | axios.get('/user/12345', { |
全局统一错误处理
在实际项目中,我们不会在每个请求的 catch
中重复写错误处理逻辑,而是通过Axios
拦截器实现全局统一的错误处理,这是最高效的方案。
首先创建 Axios 实例并配置拦截器
1 | import axios from 'axios'; |
这样,在业务代码中使用就很简单高效了
1 | import service from '@/utils/request'; |
注意,取消请求(AbortController 或
CancelToken),也会触发
catch,这类错误有一个特殊的判断方式:axios.isCancel(error)。
1 | import axios from 'axios'; |
取消请求
理解请求的取消
从 v0.22.0 开始,Axios 支持以 fetch API 方式—— AbortController
取消请求
这是个什么 API
在流式请求中我们可能知道取消请求,这个很常用,但是实际上,相比取消,流式请求的”取消”更像是“打断”,因为它的请求到服务器了,只不过是在响应输出的过程中中止了,那么这个取消是什么意思呢?
流式请求的 “取消” 是客户端 + 传输层 + 服务器层的协同行为,但不同层面的 “取消” 效果是不一样的:
客户端:
AbortController调用abort()后立刻生效的行为,也是我们最直观感受到的 “取消”,也就是客户端不收数据了传输层层面(TCP 的 “取消”:断开连接):当客户端触发取消后,底层的 TCP 协议会做出响应
- 如果是HTTP/1.1:客户端会向服务器发送
FIN包,关闭 TCP 连接(或重置连接RST)。服务器在尝试继续发送数据时,会发现连接已断开,从而停止传输。 - 如果是HTTP/2:支持流的单独取消(HTTP/2
的多路复用特性),客户端会发送
RST_STREAM帧,只终止当前的流式请求流,不会影响同连接的其他请求。
这一步是客户端取消后,传输层自动完成的,相当于 “切断了客户端和服务器之间的数据线”。
- 如果是HTTP/1.1:客户端会向服务器发送
服务器:这是最关键的一层,也是很多人误以为 “取消没用” 的原因 ——默认情况下,服务器不会因为客户端取消连接而停止处理请求。服务器需要主动做适配处理,才能实现 “真正的取消(停止处理)”。
普通请求中的取消,也就是使用AbortController,是差不多的
当你调用controller.abort()时,客户端会立刻执行以下操作:
- 终止请求实例:Axios/fetch 的请求对象会立刻停止后续的所有行为,不再等待服务器的响应。
- 触发取消错误:请求的 Promise
会被拒绝,抛出可识别的取消错误(Axios
中可通过
axios.isCancel()判断)。 - 终止前端业务逻辑:比如取消后,前端不会再执行请求成功后的渲染、数据处理等逻辑。
简单说:客户端直接放弃了这个请求的 “结果等待”,无论服务器后续是否返回数据,客户端都不会处理了。
普通请求的取消在传输层的行为,取决于你在哪个阶段调用了abort(),这是和流式请求最大的不同点:
| 请求阶段 | 传输层行为 |
|---|---|
| 请求还未发送完成 | TCP
连接会发送RST(重置)包,直接中断请求的发送,服务器甚至可能没收到完整的请求。 |
| 请求已发送,服务器未响应 | TCP 连接会关闭,服务器后续返回的响应数据会因为连接断开而无法到达客户端。 |
| 服务器已开始返回响应 | 客户端会停止接收剩余的响应数据(即使响应还没传完),直接终止连接。 |
而和流式请求一样,服务器层面,默认情况下,服务器不会因为客户端的取消而停止处理请求
AbortController
AbortController是浏览器(也兼容 Node.js
环境)提供的一个原生
API,作用是主动终止一个或多个正在进行的异步操作(比如网络请求、数据流处理等)。
通常情况下,用到取消请求的位置比较多
AbortController构造函数:创建一个控制器实例,实例包含:
signal属性:一个AbortSignal对象,用于传递取消信号,可绑定到异步操作上。abort()方法:调用该方法时,会触发signal的abort事件,并将signal.aborted设为true,通知绑定的异步操作取消。
AbortSignal对象:作为
“信号载体”,异步操作会监听这个对象的状态变化,一旦收到取消信号就停止执行。
简单来说,AbortController的工作逻辑是创建控制器
→ 把信号绑定到异步操作 →
调用abort()方法触发取消。
普通 Axios 请求中取消请求
将
AbortController的signal传入请求配置中,需要取消时调用abort()方法。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// 1. 导入Axios
import axios from 'axios';
// 2. 创建AbortController实例
const controller = new AbortController();
const { signal } = controller;
// 3. 发送Axios请求,将signal传入配置
const fetchData = async () => {
try {
const response = await axios.get('https://api.example.com/data', {
signal: signal, // 绑定取消信号
});
console.log('请求成功:', response.data);
} catch (error) {
// 捕获取消请求的错误,区分普通错误和取消错误
if (axios.isCancel(error)) {
console.log('请求被取消:', error.message);
} else {
console.log('请求失败:', error.message);
}
}
};
// 4. 调用请求
fetchData();
// 5. 手动触发取消(比如点击按钮、定时器等场景)
// 示例:3秒后取消请求
setTimeout(() => {
controller.abort('用户主动取消请求'); // 可传入自定义取消信息
}, 3000);如果需要同时取消多个请求,只需将同一个
signal传入所有请求的配置中,调用一次abort()即可批量取消:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15const controller = new AbortController();
const { signal } = controller;
// 请求1
axios.get('https://api.example.com/data1', { signal })
.catch(err => axios.isCancel(err) && console.log('请求1被取消'));
// 请求2
axios.post('https://api.example.com/data2', { name: 'test' }, { signal })
.catch(err => axios.isCancel(err) && console.log('请求2被取消'));
// 批量取消
setTimeout(() => {
controller.abort('批量取消所有请求');
}, 2000);
流式请求(比如后端返回流式数据,如大文件下载、实时日志推送、AI
对话流式响应)的取消,同样依赖AbortController,但需要结合流式响应的处理逻辑(如ReadableStream)来实现。
以 AI 对话流式响应为例
1 | import axios from 'axios'; |
- 即使调用了
abort(),已经读取的流式数据不会被回滚,只会停止后续数据的读取。
请求体编码
请求体编码的核心是将 JavaScript
对象转换为特定格式的字符串(或二进制数据),并通过Content-Type请求头告诉服务器
“该如何解析这些数据”。
Axios 作为 HTTP
客户端,会根据你传入的data类型和Content-Type头,自动或手动处理编码逻辑,常见的编码格式有
3 种:
- application/json:Axios 默认格式,将对象序列化为 JSON 字符串。
- application/x-www-form-urlencoded:表单默认格式,将对象序列化为
key1=value1&key2=value2的键值对字符串。 - multipart/form-data:用于上传文件 / 二进制数据,将数据拆分为多个部分传输。
默认编码application/json
当你向 Axios 传入普通 JavaScript 对象作为data时,Axios
会自动:
将对象序列化为JSON 字符串(等价于
JSON.stringify(data))。设置请求头
Content-Type: application/json;charset=utf-8。服务器端需要用 JSON 解析器(如 Express 的
express.json())来解析请求体。1
2
3
4
5
6
7
8
9
10
11
12
13import axios from 'axios';
// 普通对象作为data
const data = {
name: '张三',
age: 20,
hobbies: ['篮球', '游戏']
};
// Axios自动序列化为JSON,设置Content-Type
axios.post('/api/user', data)
.then(res => console.log(res))
.catch(err => console.log(err));
application/x-www-form-urlencoded 编码(表单键值对)
这种格式是传统 HTML
表单的默认提交格式,特点是数据为key=value的键值对,多个键值对用&分隔。Axios
不会自动处理这种编码
在浏览器环境下,我们一般的实现方式是使用 qs
库,npm install qs --save
1 | import qs from 'qs'; |
使用原生URLSearchParams也比较常见,我不习惯这么写
1 | // 创建URLSearchParams实例,添加键值对 |
Node.js
下,使用原生querystring模块,这个不支持嵌套对象,基本不用,使用url模块的URLSearchParams是更常见的,但是它好像对嵌套对象支持是有限的
1 | const axios = require('axios'); |
Node.js
下也可以使用qs库,它完全兼容浏览器环境的用法,支持嵌套对象,是
Node.js 环境处理复杂数据的首选。
说一下Axios 新特性,自动序列化,Axios 在新版本中提供了
自动序列化application/x-www-form-urlencoded
的功能,无需手动调用qs或URLSearchParams,只需设置Content-Type头即可。
1 | import axios from 'axios'; |
Axios 会将复杂数据转换为嵌套键值对格式,例如:
- 数组
arr: [1,2,3]→arr[]=1&arr[]=2&arr[]=3 - 嵌套对象
users[0].name→users[0][name]=Peter - 多维数组
arr2: [1, [2], 3]→arr2[0]=1&arr2[1][0]=2&arr2[2]=3
服务器需要开启嵌套对象解析功能
multipart/form-data 编码(文件上传)
这种格式用于传输二进制数据(如图片、视频、文件)或混合数据(文本 + 文件),常见于文件上传场景。
浏览器中可以直接使用原生FormData对象,Axios
会自动设置Content-Type: multipart/form-data。
1 | // 创建FormData实例 |
如果频繁使用 FormData,可以添加 Axios 拦截器,避免每次手动设置头:
1
2
3
4
5
6
7
8
9
10axios.interceptors.request.use(config => {
// 如果data是FormData实例,自动设置请求头
if (config.data instanceof FormData) {
Object.assign(config.headers, config.data.getHeaders());
}
return config;
});
// 之后发送FormData请求时,无需手动设置headers
axios.post('/api/upload', form).then(res => console.log(res));
Node.js
中没有原生FormData,需要使用form-data第三方库。
Multipart 实体请求
multipart/form-data是一种用于传输复杂数据(文本、二进制文件、Blob
等)的 HTTP 请求体编码格式,核心特点是:
- 数据被拆分为多个 “部分(part)”,每个部分有独立的标识(boundary 分隔符)。
- 支持同时传输文本数据和二进制数据(如图片、视频、文件),这是
application/x-www-form-urlencoded无法做到的。 - Axios 会根据传入的
data类型(如 FormData 对象)或请求头Content-Type: multipart/form-data,自动处理数据的序列化和请求头设置。
原生 FormData API
这是最传统的用法,直接使用FormData对象组装数据,Axios
会识别并自动处理请求头和序列化
上面讲了
只不过,浏览器的FormData无需手动设置请求头,Axios
会自动完成。
Axios
简化用法:postForm/putForm/patchForm别名方法
为了简化开发,Axios
提供了专门用于multipart/form-data的请求别名方法,这些方法的核心是:
- 自动设置请求头
Content-Type: multipart/form-data。 - 支持直接传入普通对象、FileList、Blob 等,无需手动创建 FormData。
浏览器
1 | // 替代axios.post + 手动设置Content-Type |
直接传递 FileList(多文件上传)
这是非常实用的功能,可直接将<input type="file" multiple>的files对象传入,Axios
会自动处理为多文件:
1 | // 场景1:直接传FileList,Axios会用字段名files[]发送所有文件 |
所有文件会以files[](或images[])为字段名,逐个添加到
FormData 中,实现多文件上传。
Axios
的multipart/form-data自动序列化
当请求头设置为Content-Type: multipart/form-data时,Axios
会自动将普通 JavaScript 对象序列化为 FormData
对象,无需手动创建 FormData。
1 | import axios from 'axios'; |
Axios 支持通过特殊的键名后缀来定制序列化规则,解决复杂数据的处理问题:
| 后缀 | 作用 | 示例 | 序列化结果 |
|---|---|---|---|
{} |
将值通过JSON.stringify序列化为 JSON 字符串 |
'myObj{}': {x: 1, s: "foo"} |
myObj{}: "{\"x\":1,\"s\":\"foo\"}" |
[] |
将类数组对象(如 FileList)展开为多个同名字段 | 'files[]': fileInput.files |
files[]: file1, files[]: file2 |
示例代码:
1 | axios.post('https://httpbin.org/post', { |
对于包含数组、嵌套对象的普通对象,Axios 会按照括号语法自动拆解为 FormData 的键值对
1 | // 原始对象 |




