JavaScript Fetch API
什么是 Fetch API?
Fetch API 是现代浏览器提供的一个用于发起网络请求的接口,它是 XMLHttpRequest 的更强大、更灵活的替代品。Fetch API 使用 Promise,这使得处理异步操作更加简洁和直观。
它提供了一种简单、标准化的方式来跨网络异步获取资源,是现代网页应用程序中进行 AJAX 请求的首选方法。
Fetch API 是 HTML5 的一部分,在大多数现代浏览器中得到支持,但在 Internet Explorer 中不可用。
Fetch API 基础
基本语法
fetch()
方法最简单的形式只需要一个参数 - 要获取资源的 URL:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
这个简单示例展示了 Fetch API 的基本用法:
- 调用
fetch()
并传入 URL - 处理响应(将其转换为 JSON)
- 处理数据
- 捕获并处理可能的错误
Fetch 返回 Promise
fetch()
方法返回一个 Promise,表示获取响应的操作完成(或失败)。
const fetchPromise = fetch('https://api.example.com/data');
console.log(fetchPromise); // 输出: Promise {<pending>}
fetchPromise
.then(response => {
console.log('收到响应!');
return response.json();
})
.then(data => {
console.log('数据已转换为JSON!');
console.log(data);
});
处理响应
当 fetch 请求完成时,返回的 Promise 会解析为 Response 对象,该对象包含了响应的各种信息。
响应数据格式
Response 对象提供了多种方法来处理不同类型的数据:
response.json()
- 将响应解析为 JSONresponse.text()
- 将响应解析为文本response.blob()
- 将响应解析为 Blob(二进制数据)response.formData()
- 将响应解析为 FormData 对象response.arrayBuffer()
- 将响应解析为 ArrayBuffer
每个方法都返回一个 Promise,解析为相应格式的数据。
// 获取JSON数据
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data));
// 获取文本数据
fetch('https://example.com/text-file.txt')
.then(response => response.text())
.then(text => console.log(text));
// 获取图像数据
fetch('https://example.com/image.jpg')
.then(response => response.blob())
.then(blob => {
const imageUrl = URL.createObjectURL(blob);
const imageElement = document.createElement('img');
imageElement.src = imageUrl;
document.body.appendChild(imageElement);
});
检查响应状态
在处理响应之前,通常需要检查响应是否成功:
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP错误! 状态码: ${response.status}`);
}
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error('获取数据出错:', error));
Response 对象包含几个有用的属性:
response.ok
- 布尔值,表示响应是否成功(状态码在 200-299 范围内)response.status
- HTTP 状态码(如 200、404 等)response.statusText
- 状态文本(如 "OK"、"Not Found" 等)response.headers
- Headers 对象,包含响应头信息response.url
- 响应的最终 URL(可能因重定向而与请求 URL 不同)
配置 Fetch 请求
fetch()
方法接受第二个可选参数,是一个配置对象,可以自定义请求:
fetch('https://api.example.com/data', {
method: 'POST', // HTTP请求方法
headers: { // HTTP请求头
'Content-Type': 'application/json',
'Authorization': 'Bearer TOKEN'
},
body: JSON.stringify({ // 请求体
name: 'John',
age: 30
}),
mode: 'cors', // 跨域模式
cache: 'no-cache', // 缓存控制
credentials: 'same-origin', // 凭证控制
redirect: 'follow', // 重定向处理
referrerPolicy: 'no-referrer', // 引用策略
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
常用配置选项
method
: 请求方法(GET、POST、PUT、DELETE 等)headers
: 请求头对象body
: 请求体数据(适用于 POST/PUT 等方法)mode
: 请求模式(cors、no-cors、same-origin、navigate)credentials
: 是否包含凭证(omit、same-origin、include)cache
: 缓存模式(default、no-store、reload、no-cache、force-cache、only-if-cached)
发送不同类型的请求
GET 请求(获取数据)
GET 请求是默认的请求方法,用于从服务器获取数据:
fetch('https://api.example.com/users')
.then(response => response.json())
.then(users => console.log(users));
POST 请求(创建数据)
POST 请求用于向服务器发送数据,通常用于创建新资源:
fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'John Doe',
email: 'john@example.com'
})
})
.then(response => response.json())
.then(newUser => console.log('创建的用户:', newUser));
PUT 请求(更新数据)
PUT 请求用于更新服务器上的现有资源:
fetch('https://api.example.com/users/1', {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'John Updated',
email: 'updated@example.com'
})
})
.then(response => response.json())
.then(updatedUser => console.log('更新后的用户:', updatedUser));
DELETE 请求(删除数据)
DELETE 请求用于删除服务器上的资源:
fetch('https://api.example.com/users/1', {
method: 'DELETE'
})
.then(response => {
if (response.ok) {
console.log('用户已成功删除');
} else {
console.error('删除用户失败');
}
});
使用 async/await 与 Fetch
使用 async/await 可以让 Fetch API 的代码更加清晰易读:
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`HTTP错误! 状态码: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error('获取数据出错:', error);
}
}
fetchData();
这种写法避免了多层 .then()
链,使代码更容易理解和维护。
处理错误
使用 Fetch API 时,需要注意两种类型的错误:
- 网络错误:如果请求不能完成(如网络断开),fetch 会抛出错误,触发 catch 子句
- HTTP 错误:如果服务器返回错误状态码(如 404、500),fetch 不会自动抛出错误,需要检查
response.ok
或response.status
fetch('https://non-existent-url.org/data')
.then(response => {
// 这一步检查HTTP错误
if (!response.ok) {
throw new Error(`HTTP错误! 状态码: ${response.status}`);
}
return response.json();
})
.then(data => console.log('成功:', data))
.catch(error => {
// 这一步捕获网络错误和上面抛出的HTTP错误
console.error('错误:', error);
});
中止 Fetch 请求
使用 AbortController 可以中止正在进行的 fetch 请求:
// 创建一个AbortController实例
const controller = new AbortController();
const signal = controller.signal;
// 发起请求,并传递signal
fetch('https://api.example.com/large-data', { signal })
.then(response => response.json())
.then(data => console.log(data))
.catch(error => {
if (error.name === 'AbortError') {
console.log('获取请求被用户取消');
} else {
console.error('其他错误:', error);
}
});
// 某个事件触发时中止请求
document.querySelector('#cancel-button').addEventListener('click', () => {
controller.abort();
console.log('请求已被中止');
});
实际案例:构建简单的天气应用
以下是一个使用 Fetch API 构建简单天气应用的示例:
const API_KEY = 'your_api_key'; // 需要替换为实际的API密钥
async function getWeather(city) {
try {
// 获取天气数据
const response = await fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${API_KEY}`
);
if (!response.ok) {
throw new Error(`无法获取天气数据:${response.status}`);
}
const data = await response.json();
// 更新UI
document.querySelector('#city').textContent = data.name;
document.querySelector('#temperature').textContent = `${Math.round(data.main.temp)}°C`;
document.querySelector('#description').textContent = data.weather[0].description;
document.querySelector('#humidity').textContent = `湿度:${data.main.humidity}%`;
document.querySelector('#wind-speed').textContent = `风速:${data.wind.speed} m/s`;
// 更新天气图标
const iconCode = data.weather[0].icon;
const iconUrl = `https://openweathermap.org/img/wn/${iconCode}@2x.png`;
document.querySelector('#weather-icon').src = iconUrl;
document.querySelector('#weather-icon').alt = data.weather[0].description;
} catch (error) {
console.error('获取天气数据时出错:', error);
document.querySelector('#error-message').textContent = `错误: ${error.message}`;
}
}
// 搜索表单提交事件处理
document.querySelector('#weather-form').addEventListener('submit', function(e) {
e.preventDefault();
const city = document.querySelector('#city-input').value.trim();
if (city) {
getWeather(city);
}
});
// 页面加载时默认显示北京的天气
document.addEventListener('DOMContentLoaded', () => {
getWeather('Beijing');
});
相应的HTML结构可能如下:
<div class="weather-app">
<h1>天气应用</h1>
<form id="weather-form">
<input type="text" id="city-input" placeholder="输入城市名称" required />
<button type="submit">获取天气</button>
</form>
<div id="error-message" class="error"></div>
<div class="weather-info">
<h2 id="city">--</h2>
<div class="weather-main">
<img id="weather-icon" src="" alt="" />
<div class="temperature-container">
<span id="temperature">--</span>
<span id="description">--</span>
</div>
</div>
<div class="weather-details">
<p id="humidity">湿度:--</p>
<p id="wind-speed">风速:--</p>
</div>
</div>
</div>
总结
Fetch API 是现代 JavaScript 中进行网络请求的标准方式,它比传统的 XMLHttpRequest 更简洁、更强大。主要优点包括:
- 基于 Promise 的简洁语法
- 灵活的响应处理
- 直观的请求配置
- 与现代 JavaScript 特性(如 async/await)的良好集成
通过掌握 Fetch API,你可以轻松地从服务器请求数据、提交表单、上传文件,以及与各种 Web API 进行交互,这是构建现代 Web 应用程序的基础技能之一。
练习与挑战
- 基础练习:使用 Fetch API 获取一个公开 API(如 JSONPlaceholder)的数据,并在页面上显示
- 中级练习:创建一个表单,使用 Fetch 发送 POST 请求,并处理服务器响应
- 高级挑战:构建一个小型应用,结合 GET、POST、PUT 和 DELETE 请求,实现对资源的完整 CRUD 操作
额外资源
- MDN Web Docs - Fetch API
- JavaScript.info - Fetch
- 公共 API 列表 - 用于练习 Fetch API 的免费 API 集合
记住,尽管 Fetch API 在现代浏览器中得到广泛支持,但在支持旧浏览器(特别是 IE)的项目中,你可能需要使用 polyfill 或考虑使用 Axios 等替代库。