在现代 Web 开发中,前后端通信是不可或缺的一环。从最早的 XMLHttpRequest 到轻量级的 ofetch,前端 HTTP 请求方案经历了多次迭代。不同的方案在语法风格、功能支持、体积大小、浏览器兼容性等方面各有侧重。
本文将对 XHR、AJAX、Axios、Fetch、Ky、ofetch 和 redaxios 等方案进行系统对比,帮助你在不同项目场景中做出合适的技术选型。
一、XHR 及基于 XHR 封装的库
XHR(XMLHttpRequest)
2000 年随 IE 5 诞生,是浏览器发送 HTTP 请求的原始 API。通过事件回调驱动,支持同步和异步请求,但语法较为繁琐。
AJAX(Asynchronous JavaScript and XML)
不是一个具体的技术,而是利用 XHR 或其他技术(如 fetch)实现异步数据交互的编程模式总称。jQuery 的 $.ajax 是其最知名的封装。
Axios
基于 Promise 的第三方 HTTP 库,浏览器端底层使用 XHR,Node.js 端使用 http 模块。支持请求/响应拦截器、超时、进度监听、自动 JSON 处理,是目前企业级项目中使用最广泛的方案。
二、Fetch 及基于 Fetch 封装的库
Fetch
2015 年起浏览器原生支持的现代 HTTP API,基于 Promise,语法简洁。Node.js 18 起也开始原生支持。但不支持上传/下载进度,错误处理需手动判断状态码。
ky
基于 Fetch 的轻量级封装库,提供更友好的 API,内置重试、超时、前缀配置和 hooks(类拦截器),压缩后约 3.5KB。
ofetch
Nuxt 团队出品的 Fetch 封装库,体积仅约 1.2KB。内置智能 JSON 处理、自动重试、超时和拦截器。Nuxt 3 默认集成,也适用于任何 Vite 或 Node.js 项目。
redaxios
API 完全兼容 axios,但底层使用 Fetch 而非 XHR。体积约 1.5KB,适合希望从 axios 平滑迁移到 Fetch 的项目。
umi-request
由 Umi 框架维护的网络请求库,基于Fetch封装,提供了强大的拦截器、中间件和数据转换功能。它还在被广泛使用,但官方已不再维护,并建议用户迁移。
三、GET 和 POST 请求示例
1. XHR
GET 请求:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(JSON.parse(xhr.responseText));
}
};
xhr.send();
POST 请求:
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.example.com/data', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 201) {
console.log(JSON.parse(xhr.responseText));
}
};
xhr.send(JSON.stringify({ key: 'value' }));
2. AJAX(jQuery)
GET 请求:
$.ajax({
url: 'https://api.example.com/data',
type: 'GET',
success: function(data) {
console.log(data);
}
});
POST 请求:
$.ajax({
url: 'https://api.example.com/data',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ key: 'value' }),
success: function(data) {
console.log(data);
}
});
3. Axios
GET 请求:
axios.get('https://api.example.com/data')
.then(response => console.log(response.data))
.catch(error => console.error(error));
POST 请求:
axios.post('https://api.example.com/data', { key: 'value' })
.then(response => console.log(response.data))
.catch(error => console.error(error));
4. Fetch
GET 请求:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
POST 请求:
fetch('https://api.example.com/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: 'value' })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
5. Ky
GET 请求:
import ky from 'ky';
ky.get('https://api.example.com/data')
.json()
.then(data => console.log(data))
.catch(error => console.error(error));
POST 请求:
import ky from 'ky';
ky.post('https://api.example.com/data', { json: { key: 'value' } })
.json()
.then(data => console.log(data))
.catch(error => console.error(error));
6. ofetch
GET 请求:
import { ofetch } from 'ofetch';
const data = await ofetch('https://api.example.com/data');
console.log(data);
POST 请求:
import { ofetch } from 'ofetch';
const data = await ofetch('https://api.example.com/data', {
method: 'POST',
body: { key: 'value' } // 对象会自动序列化为 JSON
});
console.log(data);
7. redaxios
GET 请求:
import axios from 'redaxios';
const { data } = await axios.get('https://api.example.com/data');
console.log(data);
POST 请求:
import axios from 'redaxios';
const { data } = await axios.post('https://api.example.com/data', {
key: 'value'
});
console.log(data);
四、不同方案的关键差异解读
1. 为什么 Axios 仍是主流?
Axios 的周下载量稳居高位。这源于三个不可替代的优势:
- 拦截器体系:请求/响应拦截器链式调用,轻松实现 Token 注入、401 刷新、统一错误处理。
- 进度事件:
onUploadProgress和onDownloadProgress,文件上传下载的刚需。 - 同构能力:同一份代码在浏览器和 Node.js 端运行,Next.js/Nuxt 等全栈框架的最佳拍档。
2. Fetch 生态为什么增速明显?
2022 年 IE 退役,Node.js 18 原生支持 Fetch,Fetch 正式成为 JavaScript 生态中真正的“同构 API”。ky、ofetch、redaxios 都是基于 Fetch 的封装,保留了 ReadableStream 流式处理能力,这在 AI 对话逐字输出、大文件分块下载等场景中至关重要——这是 Axios 做不到的。
3. 为什么需要ky、ofetch 和 redaxios?
- ky:轻量级封装库,压缩后约 3.5KB,提供更友好的 API,内置重试、超时、前缀配置和 hooks(类拦截器)。下载量如下图:
- ofetch:体积仅 1.2KB,Nuxt 3 默认集成,SSR 场景开箱即用。如果不需进度条且用 Nuxt,这是最优解。下载量如下图:
- redaxios:API 完全兼容 axios,但底层是 Fetch。适合想从 axios 迁移但不想改代码的项目。下载量如下图:
五、总而言之
选择 HTTP 请求方案时,没有“最好”,只有“最合适”。
-
如果你的项目追求企业级功能与生态,比如需要完善的拦截器体系、上传下载进度监听以及浏览器与 Node.js 的同构能力,那么 Axios 依然是当前最成熟的选择。
-
若你更看重极致的体积与现代性,希望基于 Fetch 获得简洁的 API 并内置重试、超时等常用特性,Ky 会是一个非常轻量的方案。
-
对于 Nuxt 3 项目,由于 ofetch 已被默认集成,它在服务端渲染场景下开箱即用,是这类应用的最优选。
-
假如团队希望从 Axios 平稳迁移到底层 Fetch,却又不想大规模修改现有业务代码,redaxios 提供了几乎完全兼容的接口,可以作为过渡方案。
-
而在追求零依赖和流式处理的场景中,例如需要消费 AI 对话的逐字输出或进行大文件的分块下载,原生 Fetch 便成为最直接的选择,它能让你完全掌控 ReadableStream 且不引入任何额外依赖。
-
至于正在维护的老项目,技术栈已经稳定且运行良好,继续使用现有的请求方案即可,不必为了更换而更换,除非有明确的性能或维护收益。
无论选择哪种方案,封装一个统一的 request 层才是最重要的——它将让你在未来无痛切换底层库,而不用改动一行业务代码。
你的项目中用的是什么请求方案?都踩过什么坑?欢迎评论区分享你的见解。