Ajax、Axios、Fetch 对比
三种 HTTP 请求方式的区别与使用场景
问题
Ajax、Axios、Fetch 三种请求方式有什么区别?各自的优缺点是什么?
解答
Ajax (XMLHttpRequest)
最传统的异步请求方式,基于 XMLHttpRequest 对象。
// 原生 Ajax 请求
function ajax(url, method = 'GET', data = null) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open(method, url, true)
// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.responseText))
} else {
reject(new Error(xhr.statusText))
}
}
}
// 错误处理
xhr.onerror = function () {
reject(new Error('Network Error'))
}
// 发送请求
xhr.send(data ? JSON.stringify(data) : null)
})
}
// 使用
ajax('/api/users', 'GET')
.then(data => console.log(data))
.catch(err => console.error(err))
Fetch
浏览器原生 API,基于 Promise,语法更简洁。
// 基本 GET 请求
fetch('/api/users')
.then(response => {
// 注意:HTTP 错误状态不会 reject
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
return response.json()
})
.then(data => console.log(data))
.catch(err => console.error(err))
// POST 请求
fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'John' })
})
.then(response => response.json())
.then(data => console.log(data))
// async/await 写法
async function getUsers() {
try {
const response = await fetch('/api/users')
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const data = await response.json()
return data
} catch (error) {
console.error('Fetch error:', error)
}
}
Axios
第三方库,基于 Promise 封装 XMLHttpRequest,功能更丰富。
// GET 请求
axios.get('/api/users')
.then(response => console.log(response.data))
.catch(error => console.error(error))
// POST 请求
axios.post('/api/users', { name: 'John' })
.then(response => console.log(response.data))
// 创建实例,统一配置
const instance = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000,
headers: { 'Authorization': 'Bearer token' }
})
// 请求拦截器
instance.interceptors.request.use(
config => {
// 请求前处理,如添加 token
config.headers.Authorization = `Bearer ${getToken()}`
return config
},
error => Promise.reject(error)
)
// 响应拦截器
instance.interceptors.response.use(
response => response.data,
error => {
// 统一错误处理
if (error.response?.status === 401) {
// 跳转登录
}
return Promise.reject(error)
}
)
// 并发请求
Promise.all([
axios.get('/api/users'),
axios.get('/api/posts')
]).then(([users, posts]) => {
console.log(users.data, posts.data)
})
对比表格
| 特性 | Ajax (XHR) | Fetch | Axios |
|---|---|---|---|
| 类型 | 浏览器内置 | 浏览器内置 | 第三方库 |
| Promise | 需手动封装 | 原生支持 | 原生支持 |
| 请求取消 | 支持 | AbortController | CancelToken |
| 超时设置 | 支持 | 需手动实现 | 支持 |
| 拦截器 | 无 | 无 | 支持 |
| 自动转换 JSON | 否 | 否 | 是 |
| 错误处理 | 手动判断 | 仅网络错误 reject | HTTP 错误也 reject |
| 浏览器兼容 | IE7+ | 现代浏览器 | IE11+(需 polyfill) |
Fetch 的注意事项
// 1. HTTP 错误不会 reject,需要手动检查
fetch('/api/404')
.then(response => {
// 即使 404,也会进入 then
console.log(response.ok) // false
console.log(response.status) // 404
})
// 2. 默认不发送 cookies
fetch('/api/users', {
credentials: 'include' // 跨域携带 cookie
// credentials: 'same-origin' // 同源携带 cookie
})
// 3. 取消请求
const controller = new AbortController()
fetch('/api/users', { signal: controller.signal })
controller.abort() // 取消请求
// 4. 超时实现
function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), timeout)
return fetch(url, { signal: controller.signal })
.finally(() => clearTimeout(timeoutId))
}
关键点
- Ajax:最原始的方式,API 繁琐,需要手动封装 Promise
- Fetch:原生 Promise 支持,但 HTTP 错误不 reject,默认不带 cookie,无超时设置
- Axios:功能最全,支持拦截器、自动转 JSON、请求取消、超时,但需要额外引入
- 选择建议:简单项目用 Fetch,复杂项目用 Axios,不推荐直接用原生 Ajax
目录