1. 概念和历史背景
-
AJAX(Asynchronous JavaScript and XML)
- 是一种在不刷新整个页面的情况下,与服务器进行异步通信并更新部分网页的技术。它并非单一的技术,而是多种技术的组合,包括
XMLHttpRequest对象、JavaScript、HTML 和 CSS 等。 - 诞生较早,在 2005 年左右开始流行,当时主要用于在网页中实现动态数据加载,打破了传统网页需要刷新整个页面才能获取新数据的局限。最初使用 XML 格式传输数据,但现在更多使用 JSON 格式。
- 是一种在不刷新整个页面的情况下,与服务器进行异步通信并更新部分网页的技术。它并非单一的技术,而是多种技术的组合,包括
-
fetch
- 是现代浏览器提供的一个用于发起网络请求的 API,基于
Promise实现,是XMLHttpRequest的一种替代方案。 - 随着 JavaScript 语言的发展,为了提供更简洁、更强大的网络请求功能而推出,是 Web API 的一部分,在较新的浏览器中得到了广泛支持。
- 是现代浏览器提供的一个用于发起网络请求的 API,基于
-
axios
- 是一个基于
Promise的 HTTP 客户端,既可以在浏览器环境中使用,也可以在 Node.js 环境中使用。 - 是一个第三方库,由开发者社区维护和开发,旨在提供更便捷、更强大的 HTTP 请求功能,弥补了
fetch和XMLHttpRequest在某些方面的不足。
- 是一个基于
相同点
// 请求都可被取消
// - xhr
xhr.abort() readyState变为0
// - fetch
const controller = new AbortController()
const signal = controller.signal
fetch(url, {signal}).then(() => ...).catch(err => if (err.name === 'AbortError'){console.log('cancel', err.message)})
controller.abort()
// - axios
const cancelToken = axios.CancelToken
let cancel
axios.get(url, {
cancelToken: new CancelToken(function(c){
cancel = c
})
}).then().catch((err) => {if (axios.isCancel(err)) {console.log('cancel', err.message)}})
cancel('user cancel')
不同点
1.xhr、fetch在get请求下参数需要手动拼接到url上(当然也可以使用URLSearchParams处理)
// 定义请求的基础 URL
const baseUrl = 'https://jsonplaceholder.typicode.com/posts';
// 定义参数对象
const params = {
userId: 1,
_sort: 'id',
_order: 'desc'
};
const searchParams = new URLSearchParams(params)
// 拼接完整的 URL
const url = `${baseUrl}?${searchParams.toString()}`;
2.xhr、fetch不带拦截器
1. 原生 JavaScript 实现 AJAX
使用原生 JavaScript 实现 AJAX 请求,主要借助 XMLHttpRequest 对象,以下是详细步骤和示例代码:
步骤
- 创建
XMLHttpRequest对象:这是发起 AJAX 请求的核心对象。 - 打开连接:使用
open()方法指定请求方法(如 GET、POST)、请求的 URL 以及是否异步等信息。 - 发送请求:使用
send()方法发送请求,如果是 POST 请求,还需要设置请求头并传递请求体数据。 - 监听状态变化:通过监听
onreadystatechange事件,获取请求的状态变化,当状态码为 200 且请求完成时,说明请求成功。 - 处理响应:根据响应的状态和内容进行相应的处理。
示例代码(GET 请求)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原生 AJAX GET 请求示例</title>
</head>
<body>
<button id="fetchDataButton">获取数据</button>
<div id="result"></div>
<script>
const fetchDataButton = document.getElementById('fetchDataButton');
const resultDiv = document.getElementById('result');
fetchDataButton.addEventListener('click', () => {
// 创建 XMLHttpRequest 对象
const xhr = new XMLHttpRequest();
// 打开连接
xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1', true);
// 监听状态变化
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// 请求成功,处理响应数据
const responseData = JSON.parse(xhr.responseText);
resultDiv.innerHTML = `<p>标题: ${responseData.title}</p>`;
}
};
// 发送请求
xhr.send();
});
</script>
</body>
</html>
示例代码(POST 请求)
收起
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原生 AJAX POST 请求示例</title>
</head>
<body>
<button id="postDataButton">发送数据</button>
<div id="postResult"></div>
<script>
const postDataButton = document.getElementById('postDataButton');
const postResultDiv = document.getElementById('postResult');
postDataButton.addEventListener('click', () => {
// 创建 XMLHttpRequest 对象
const xhr = new XMLHttpRequest();
// 打开连接
xhr.open('POST', 'https://jsonplaceholder.typicode.com/posts', true);
// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/json');
// 准备请求体数据
const data = {
title: 'foo',
body: 'bar',
userId: 1
};
const jsonData = JSON.stringify(data);
// 监听状态变化
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 201) {
// 请求成功,处理响应数据
const responseData = JSON.parse(xhr.responseText);
postResultDiv.innerHTML = `<p>新帖子 ID: ${responseData.id}</p>`;
}
};
// 发送请求
xhr.send(jsonData);
});
</script>
</body>
</html>
使用 jQuery 实现 AJAX
jQuery 是一个流行的 JavaScript 库,它对 XMLHttpRequest 进行了封装,提供了更简洁的 API 来实现 AJAX 请求。
示例代码(GET 请求)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>jQuery AJAX GET 请求示例</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<button id="jqueryFetchDataButton">使用 jQuery 获取数据</button>
<div id="jqueryResult"></div>
<script>
$('#jqueryFetchDataButton').on('click', function () {
$.ajax({
url: 'https://jsonplaceholder.typicode.com/todos/1',
method: 'GET',
success: function (response) {
$('#jqueryResult').html(`<p>标题: ${response.title}</p>`);
},
error: function (error) {
console.error('请求出错:', error);
}
});
});
</script>
</body>
</html>
示例代码(POST 请求)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>jQuery AJAX POST 请求示例</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<button id="jqueryPostDataButton">使用 jQuery 发送数据</button>
<div id="jqueryPostResult"></div>
<script>
$('#jqueryPostDataButton').on('click', function () {
const data = {
title: 'foo',
body: 'bar',
userId: 1
};
$.ajax({
url: 'https://jsonplaceholder.typicode.com/posts',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(data),
success: function (response) {
$('#jqueryPostResult').html(`<p>新帖子 ID: ${response.id}</p>`);
},
error: function (error) {
console.error('请求出错:', error);
}
});
});
</script>
</body>
</html>
2.Fetch的使用
fetch 是浏览器提供的一个用于发起网络请求的 API,它基于 Promise 实现,使用起来较为简洁和灵活。以下从基本使用、请求参数、处理响应、错误处理等方面详细介绍 fetch 的使用方法:
基本使用
fetch 最基本的用法是传入一个 URL 作为参数,它会发起一个 GET 请求并返回一个 Promise 对象,该 Promise 会在请求完成后被 resolve 为一个 Response 对象,代表服务器的响应。
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
console.error('Fetch error:', error);
});
代码解释:
fetch('https://api.example.com/data'):发起一个 GET 请求到指定的 URL。response.ok:检查响应的状态码是否在 200 - 299 范围内,如果不在则抛出错误。response.json():将响应的主体内容解析为 JSON 格式,它返回一个 Promise。data:最终得到的解析后的 JSON 数据。.catch():捕获请求过程中可能出现的错误并进行处理。
发送 POST 请求
如果需要发送 POST 请求,可以通过传入第二个参数(一个配置对象)来指定请求方法、请求头和请求体等信息。
const data = {
name: 'John',
age: 30
};
fetch('https://api.example.com/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(result => {
console.log(result);
})
.catch(error => {
console.error('Fetch error:', error);
});
代码解释:
method: 'POST':指定请求方法为 POST。headers:设置请求头,这里指定请求体的格式为 JSON。body: JSON.stringify(data):将 JavaScript 对象转换为 JSON 字符串作为请求体发送。
处理不同类型的响应
除了 JSON 格式的响应,fetch 还可以处理其他类型的响应,如文本、Blob 等。
处理文本响应
fetch('https://api.example.com/text')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.text();
})
.then(text => {
console.log(text);
})
.catch(error => {
console.error('Fetch error:', error);
});
处理 Blob 响应(用于下载文件等场景)
fetch('https://example.com/image.jpg')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.blob();
})
.then(blob => {
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'image.jpg';
link.click();
URL.revokeObjectURL(url);
})
.catch(error => {
console.error('Fetch error:', error);
});
设置请求超时
fetch 本身没有内置的超时机制,但可以结合 Promise.race 来实现超时功能。
function fetchWithTimeout(url, options = {}, timeout = 5000) {
const controller = new AbortController();
const signal = controller.signal;
const fetchPromise = fetch(url, { ...options, signal });
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
controller.abort();
reject(new Error('Request timed out'));
}, timeout);
});
return Promise.race([fetchPromise, timeoutPromise]);
}
fetchWithTimeout('https://api.example.com/data', { method: 'GET' }, 3000)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
console.error('Fetch error:', error);
});
代码解释:
AbortController和signal:用于取消请求。Promise.race:同时执行fetchPromise和timeoutPromise,哪个先完成就返回哪个的结果。如果超时timeoutPromise先完成,则取消请求并抛出错误。
coding time
以下为你提供几个不同场景下使用 fetch 的完整代码示例,帮助你进一步掌握它的使用。
1. 简单的 GET 请求获取 JSON 数据
这个示例会从 JSONPlaceholder 这个免费的测试 API 获取一条待办事项数据并打印出来。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fetch GET Example</title>
</head>
<body>
<script>
// 发起 GET 请求
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => {
// 检查响应状态
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// 将响应数据解析为 JSON
return response.json();
})
.then(data => {
console.log('获取到的数据:', data);
})
.catch(error => {
console.error('请求出错:', error);
});
</script>
</body>
</html>
2. 发送 POST 请求
下面的代码会向 JSONPlaceholder 的 API 发送一个 POST 请求,模拟创建一条新的待办事项。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fetch POST Example</title>
</head>
<body>
<script>
// 要发送的数据
const todoData = {
title: '完成前端项目',
completed: false
};
// 发起 POST 请求
fetch('https://jsonplaceholder.typicode.com/todos', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(todoData)
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('创建成功,返回的数据:', data);
})
.catch(error => {
console.error('请求出错:', error);
});
</script>
</body>
</html>
3. 处理文本响应
此示例会从一个简单的文本文件 URL 获取文本内容并显示在页面上。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fetch Text Response Example</title>
</head>
<body>
<div id="text-container"></div>
<script>
const textContainer = document.getElementById('text-container');
// 发起 GET 请求获取文本
fetch('https://example.com/sample.txt')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.text();
})
.then(text => {
textContainer.textContent = text;
})
.catch(error => {
console.error('请求出错:', error);
textContainer.textContent = '无法获取文本内容';
});
</script>
</body>
</html>
4. 实现请求超时
下面代码实现了一个带有超时功能的 fetch 请求,若请求超过设定时间还未完成,会终止请求并报错。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fetch with Timeout Example</title>
</head>
<body>
<script>
function fetchWithTimeout(url, options = {}, timeout = 5000) {
const controller = new AbortController();
const signal = controller.signal;
const fetchPromise = fetch(url, { ...options, signal });
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
controller.abort();
reject(new Error('请求超时'));
}, timeout);
});
return Promise.race([fetchPromise, timeoutPromise]);
}
fetchWithTimeout('https://jsonplaceholder.typicode.com/todos/1', { method: 'GET' }, 3000)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('获取到的数据:', data);
})
.catch(error => {
console.error('请求出错:', error);
});
</script>
</body>
</html>
3.Axios的使用
Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js 环境。它具有很多优点,比如支持拦截请求和响应、转换请求和响应数据、自动转换 JSON 数据等。以下是 Axios 的详细使用方法:
安装
- 在浏览器中使用:可以通过 CDN 引入 Axios,在 HTML 文件的
<head>标签中添加如下代码:
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
- 在 Node.js 项目中使用:使用 npm 或 yarn 进行安装,在项目根目录下执行以下命令:
npm install axios
# 或者
yarn add axios
基本使用
发送 GET 请求
// 浏览器环境示例
axios.get('https://jsonplaceholder.typicode.com/todos/1')
.then(response => {
console.log('响应数据:', response.data);
})
.catch(error => {
console.error('请求出错:', error);
});
// Node.js 环境示例
const axios = require('axios');
axios.get('https://jsonplaceholder.typicode.com/todos/1')
.then(response => {
console.log('响应数据:', response.data);
})
.catch(error => {
console.error('请求出错:', error);
});
发送 POST 请求
const data = {
title: 'foo',
body: 'bar',
userId: 1
};
axios.post('https://jsonplaceholder.typicode.com/posts', data)
.then(response => {
console.log('响应数据:', response.data);
})
.catch(error => {
console.error('请求出错:', error);
});
使用 async/await 语法
async function fetchData() {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/todos/1');
console.log('响应数据:', response.data);
} catch (error) {
console.error('请求出错:', error);
}
}
fetchData();
配置请求
在发送请求时,可以传递一个配置对象来设置请求的各种参数,如请求头、超时时间等。
axios({
method: 'get',
url: 'https://jsonplaceholder.typicode.com/todos/1',
headers: {
'Content-Type': 'application/json'
},
timeout: 5000 // 设置超时时间为 5 秒
})
.then(response => {
console.log('响应数据:', response.data);
})
.catch(error => {
if (error.code === 'ECONNABORTED') {
console.error('请求超时');
} else {
console.error('请求出错:', error);
}
});
拦截器
Axios 允许在请求或响应被处理之前对其进行拦截,可用于添加请求头、日志记录等操作。
// 添加请求拦截器
axios.interceptors.request.use(config => {
// 在发送请求之前做些什么
console.log('请求拦截器:', config);
// 可以在这里添加请求头
config.headers.Authorization = 'Bearer your_token';
return config;
}, error => {
// 对请求错误做些什么
console.error('请求拦截器错误:', error);
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(response => {
// 对响应数据做点什么
console.log('响应拦截器:', response);
return response;
}, error => {
// 对响应错误做点什么
console.error('响应拦截器错误:', error);
return Promise.reject(error);
});
取消请求
在某些情况下,可能需要取消正在进行的请求。可以使用 CancelToken 来实现。
const CancelToken = axios.CancelToken;
let cancel;
axios.get('https://jsonplaceholder.typicode.com/todos/1', {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
})
.then(response => {
console.log('响应数据:', response.data);
})
.catch(error => {
if (axios.isCancel(error)) {
console.log('请求已取消:', error.message);
} else {
console.error('请求出错:', error);
}
});
// 取消请求
cancel('请求被用户取消');
并发请求
Axios 提供了 axios.all 方法来处理并发请求,使用 axios.spread 来处理多个响应。
function getUserAccount() {
return axios.get('https://jsonplaceholder.typicode.com/users/1');
}
function getUserPermissions() {
return axios.get('https://jsonplaceholder.typicode.com/permissions/1');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread((accountResponse, permissionsResponse) => {
console.log('用户账户信息:', accountResponse.data);
console.log('用户权限信息:', permissionsResponse.data);
}))
.catch(error => {
console.error('请求出错:', error);
});
以上就是 Axios 的常见使用方法,你可以根据具体需求灵活运用这些功能。