
其实很多人对这俩工具的认知都停留在“能发请求”的表层,却没搞透背后的本质差异。这篇文章就把Axios和Ajax的区别扒得明明白白:从“Ajax是原生技术方案(靠XMLHttpRequest实现),Axios是封装后的工具库”的底层逻辑,到“写POST请求要写多少行代码”的实际用法,再到“旧项目兼容IE得选谁、新项目追求效率该用谁”的场景选择,甚至连“错误处理是不是更方便”“能不能拦截请求响应”这些细节都没放过。
读完你会发现,原来不是两者“差不多”,而是各自有明确的适用边界——搞懂这些,下次写请求时再也不用犹豫选哪个,也不会再把两种写法混着用了。
你有没有过这种经历?接手一个前端项目,里面既有同事写的axios.get
,又有老代码里的new XMLHttpRequest()
,改个请求逻辑得来回翻文档,生怕把两种写法搞混;或者自己写代码时,纠结到底用Axios还是原生Ajax,总担心“选了这个会不会后期麻烦”?其实不用慌——这篇就把Axios和Ajax的区别扒得明明白白,从本质到实操,看完你再选工具,肯定不会再犯迷糊。
从本质到出身:Axios和Ajax不是一个层面的东西
先得把最核心的认知纠过来:Axios和Ajax压根不是“同类”——Ajax是“异步请求”的技术方案,而Axios是帮你“更轻松实现Ajax”的工具库。这话怎么理解?举个例子:Ajax就像“做饭”这个概念,而Axios是“电饭煲”——你用锅铲炒菜(原生Ajax)是做饭,用电饭煲焖饭(Axios)也是做饭,但电饭煲把“生火、加水、盯着火候”这些步骤都替你做了,更省心。
具体说,Ajax的核心是XMLHttpRequest(简称XHR)——这是浏览器内置的API,能让你在不刷新页面的情况下,向服务器发送请求、接收数据。比如原生写Ajax得这么干:
// 创建XHR对象
var xhr = new XMLHttpRequest();
//
初始化请求(方法、地址、异步)
xhr.open('GET', 'https://api.example.com/user', true);
//
发送请求
xhr.send();
//
监听状态变化,处理响应
xhr.onreadystatechange = function() {
// readyState=4表示请求完成
if (xhr.readyState === 4) {
// status=200表示成功
if (xhr.status === 200) {
console.log('用户数据:', JSON.parse(xhr.responseText));
} else {
console.error('请求失败,状态码:', xhr.status);
}
}
};
//
监听网络错误
xhr.onerror = function() {
console.error('网络连接失败');
};
你看,光是发个GET请求,就得写5步:创建对象、初始化、发送、监听状态、处理错误。要是写POST请求,还得额外设置Content-Type
、把数据转成JSON字符串——步骤多不说,还容易漏写(比如我之前帮朋友改旧项目,他漏了JSON.parse
,结果拿到的是字符串,调试了半小时才发现)。
而Axios呢?它是基于Promise封装的HTTP客户端,把原生Ajax的这些“重复步骤”全打包了。比如同样的GET请求,Axios只要写:
axios.get('https://api.example.com/user')
.then(res => console.log('用户数据:', res.data))
.catch(err => console.error('请求失败:', err.message));
不用创建XHR对象,不用监听readyState
,甚至不用手动解析JSON——Axios会自动把响应体转成JavaScript对象。更关键的是,它用了Promise的链式调用,解决了原生Ajax的“回调地狱”问题(比如多个请求依赖时,不用嵌套多层onreadystatechange
)。
我去年帮一个做本地生活服务的客户改项目,他们的旧代码里全是原生Ajax,光“获取商家列表+获取商品分类”就写了80行代码,嵌套了3层回调。换成Axios之后,代码直接缩到30行,还加了请求拦截器(每次请求自动带token),客户的开发小哥说:“现在改接口只需要改一行baseURL,再也不用找遍整个文件改地址了。”
实操里的区别:用一次就知道谁更顺手
光讲本质不够,实操中的差异才是你选工具的关键。我把前端开发里最常遇到的场景列出来,对比Axios和原生Ajax的表现——看完你就知道,为什么现在90%的新项目都用Axios。
先看POST请求(前端最常用的场景,比如登录、提交表单):
var xhr = new XMLHttpRequest();
xhr.open('POST', '/login', true);
// 手动设置请求头(告诉服务器我发的是JSON)
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log('登录成功:', JSON.parse(xhr.responseText));
}
};
// 手动把对象转成JSON字符串
var data = JSON.stringify({ username: 'admin', password: '123456' });
xhr.send(data);
Axios只需要:
javascript
axios.post('/login', { username: 'admin', password: '123456' })
.then(res => console.log('登录成功:', res.data))
.catch(err => console.error('登录失败:', err.response.data.msg));
Content-Type: application/json
有没有发现?Axios帮你做了3件事:
自动设置 (不用手动写
setRequestHeader);
data
自动把 对象转成JSON字符串(不用
JSON.stringify);
JSON.parse
自动解析响应体为JavaScript对象(不用 )。
再比如多个请求依赖(比如先拿用户ID,再用ID拿订单):
原生Ajax得嵌套回调:
javascript
var xhr = new XMLHttpRequest();
xhr.open('GET', '/user', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var userId = JSON.parse(xhr.responseText).id;
// 嵌套第二个请求
var xhr2 = new XMLHttpRequest();
xhr2.open('GET', '/orders/' + userId, true);
xhr2.onreadystatechange = function() {
if (xhr2.readyState === 4 && xhr2.status === 200) {
console.log('用户订单:', JSON.parse(xhr2.responseText));
}
};
xhr2.send();
}
};
xhr.send();
Axios用链式调用:
javascript
axios.get('/user')
.then(userRes => axios.get('/orders/' + userRes.data.id))
.then(orderRes => console.log('用户订单:', orderRes.data))
.catch(err => console.error('请求失败:', err));
onerror
嵌套回调有多恶心?写过的人都懂——代码像“金字塔”一样越来越深,改个逻辑得从上到下翻半天。而Axios的链式调用,把“先做A再做B”的逻辑写得明明白白,后期维护起来轻松10倍。
错误处理:Axios帮你把“坑”都填了 原生Ajax的错误处理是“分裂”的:你得同时监听
(网络错误)和
onreadystatechange里的
status(HTTP错误,比如404、500)。比如:
javascript
var xhr = new XMLHttpRequest();
xhr.open(‘GET’, ‘/data’, true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
// HTTP状态码200-299是成功
if (xhr.status >= 200 && xhr.status < 300) {
console.log(‘成功:’, xhr.responseText);
} else {
console.error(‘HTTP错误:’, xhr.status);
}
}
};
// 网络错误(比如断网)会触发这个
xhr.onerror = function() {
console.error(‘网络连接失败’);
};
要是漏写了
onerror,断网时页面就没反应,用户还以为是自己没点到;要是漏判断
status,404的时候也会进“成功”逻辑——我之前做过一个商品详情页,就因为漏了
status判断,用户点“加入购物车”时,接口返回401(未登录),页面还提示“加入成功”,差点被测试小姐姐骂死。
catchAxios的错误处理是统一的:所有错误(网络错误、HTTP错误、代码错误)都会进
回调,而且能明确区分错误类型:
javascript
axios.get(‘/data’)
.then(res => console.log(‘成功:’, res.data))
.catch(err => {
if (err.response) {
// HTTP错误:比如404、500,err.response里有状态码和响应体
console.error(‘HTTP错误:’, err.response.status, err.response.data);
} else if (err.request) {
// 网络错误:发了请求但没收到响应(比如断网)
console.error(‘网络错误:’, err.request);
} else {
// 其他错误:比如请求前的代码写错了
console.error(‘请求失败:’, err.message);
}
});
这样一来,不管是断网还是接口报错,你都能在
catch里统一处理——比如弹个提示框“请求失败,请检查网络”,或者“账号未登录,请重新登录”,用户体验直接拉满。
setRequestHeader扩展能力:Axios能做的,原生Ajax得“自己造轮子” Axios的拦截器(Interceptors)是它最香的功能之一——能在请求发送前、响应返回后“插一脚”,做一些全局处理。比如:
请求拦截器:给所有请求加token(不用每个请求都写 );
javascript
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = 'Bearer ' + token;
}
return config;
});
{ code: 200, data: ... }
响应拦截器:统一处理响应数据(比如接口返回 ,直接返回
data,不用每次都写
res.data.data);
javascript
axios.interceptors.response.use(res => {
if (res.data.code === 200) {
return res.data.data; // 只返回有用的数据
} else {
// 非200状态码,抛错到catch
return Promise.reject(res.data.msg);
}
});
要是用原生Ajax做这些,你得自己封装一个“超级函数”——比如:
javascript
function ajax(method, url, data) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open(method, url, true);
// 加token(全局处理)
const token = localStorage.getItem(‘token’);
if (token) {
xhr.setRequestHeader(‘Authorization’, ‘Bearer ‘ + token);
}
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
const res = JSON.parse(xhr.responseText);
if (res.code === 200) {
resolve(res.data); // 统一返回data
} else {
reject(res.msg);
}
} else {
reject(‘HTTP错误:’ + xhr.status);
}
}
};
xhr.onerror = function() {
reject(‘网络错误’);
};
xhr.send(JSON.stringify(data));
});
}
这还只是基础版,要是想加更多功能(比如超时处理、取消请求),函数得写得更复杂——而Axios已经把这些功能“内置”了,你直接用就行。比如取消请求(比如用户快速点击按钮,取消前一次请求):
javascript
const source = axios.CancelToken.source();
// 发送请求
axios.get(‘/data’, { cancelToken: source.token })
.catch(err => {
if (axios.isCancel(err)) {
console.log(‘请求被取消:’, err.message);
}
});
// 取消请求(比如用户点击“取消”按钮)
source.cancel(‘用户主动取消请求’);
原生Ajax要做取消请求,得调用
xhr.abort(),还得处理
onabort事件——比Axios麻烦多了。
最后说兼容性——这是原生Ajax仅有的“优势”:
es6-promise的polyfill(比如:
)。
我去年帮一个国企做内部OA系统,他们要求兼容IE10,一开始用Axios,结果IE下报错“Promise未定义”,后来加了polyfill才解决。要是项目不用兼容旧IE,Axios的兼容性完全没问题;要是得兼容IE8,那可能得用原生Ajax或者jQuery的
$.ajax(不过jQuery现在也不推荐用了)。
一张表帮你快速区分:Axios vs Ajax
为了让你更清楚,我把关键区别做成了表格——下次选工具前,看这张表就行:
对比项 | Axios | 原生Ajax(XMLHttpRequest) |
---|---|---|
本质 | 基于Promise的HTTP客户端库 | 异步请求的技术方案(核心API) |
语法复杂度 | 极简,链式调用,自动处理JSON | 繁琐,需手动处理XHR的所有步骤 |
错误处理 | 统一catch,区分网络/HTTP/其他错误 | 需分开监听onerror和readyState |
扩展能力 | 支持拦截器、全局配置、取消请求 | 需自己封装函数,扩展成本高 |
兼容性 | 默认IE11+,需polyfill兼容旧版 | 兼容到IE6,无需额外处理 |
看到这,你应该能明白:Axios不是“取代”Ajax,而是“优化”Ajax的使用体验。要是你做新项目,优先选Axios——代码简洁、功能全、维护容易;要是改旧项目,里面全是原生Ajax,也不用急着全换掉,但可以慢慢用Axios替换重复的代码;要是得兼容很老的IE,那原生Ajax或者jQuery的Ajax可能更适合。
你最近在项目里用Axios或者Ajax遇到过什么坑?评论区聊两句,我帮你分析分析怎么解决!
本文常见问题(FAQ)
Axios和Ajax本质上有什么不一样?
其实Axios和Ajax压根不是同类——Ajax是“异步请求”的技术方案,核心是浏览器内置的XMLHttpRequest(XHR)API,就像“做饭”这个概念;而Axios是帮你更轻松实现Ajax的工具库,类似“电饭煲”,把原生Ajax里“创建XHR对象、设置请求头、解析JSON”这些复杂步骤都打包好了,用起来更省心。
新项目优先选Axios还是原生Ajax?
肯定优先选Axios啊!新项目讲究效率和维护性,Axios语法简洁到“发个GET请求只要一行axios.get”,不用手动处理XHR的各种细节;还支持拦截器(比如全局加token、统一处理响应)、取消请求这些实用功能,代码写得快,后期改接口也只需要改一行baseURL,比原生Ajax省事儿多了。
Axios和原生Ajax的错误处理有什么区别?
原生Ajax的错误处理是“分裂”的——得同时监听onerror(网络错误,比如断网)和onreadystatechange里的status(HTTP错误,比如404),漏一个就会出问题;而Axios的错误处理是“统一”的,所有错误都进catch回调,还能明确区分类型:HTTP错误能拿到response里的status和data,网络错误能看到request对象,处理起来不用来回翻代码。
需要兼容旧IE浏览器,选Axios还是原生Ajax?
如果要兼容IE6这种很老的浏览器,优先选原生Ajax,因为它是浏览器内置的API,不用额外加东西;要是兼容到IE11,Axios也能用,但得加个es6-promise的polyfill(比如引个js文件),不然Promise会报错。要是项目不用兼容旧IE,直接选Axios就行,省事儿。
Axios的拦截器有什么用?原生Ajax能做吗?
Axios的拦截器特别实用!请求拦截器可以给所有请求自动带token(不用每个请求都写setRequestHeader),响应拦截器可以统一处理响应(比如接口返回{code:200,data:…},直接返回data,不用每次都写res.data.data)。原生Ajax要做这些,得自己封装个函数把逻辑塞进去,扩展成本比Axios高多了,不如直接用Axios的现成功能。