跳到主要内容

JavaScript Fetch API

什么是 Fetch API?

Fetch API 是现代浏览器提供的一个用于发起网络请求的接口,它是 XMLHttpRequest 的更强大、更灵活的替代品。Fetch API 使用 Promise,这使得处理异步操作更加简洁和直观。

它提供了一种简单、标准化的方式来跨网络异步获取资源,是现代网页应用程序中进行 AJAX 请求的首选方法。

备注

Fetch API 是 HTML5 的一部分,在大多数现代浏览器中得到支持,但在 Internet Explorer 中不可用。

Fetch API 基础

基本语法

fetch() 方法最简单的形式只需要一个参数 - 要获取资源的 URL:

javascript
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

这个简单示例展示了 Fetch API 的基本用法:

  1. 调用 fetch() 并传入 URL
  2. 处理响应(将其转换为 JSON)
  3. 处理数据
  4. 捕获并处理可能的错误

Fetch 返回 Promise

fetch() 方法返回一个 Promise,表示获取响应的操作完成(或失败)。

javascript
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() - 将响应解析为 JSON
  • response.text() - 将响应解析为文本
  • response.blob() - 将响应解析为 Blob(二进制数据)
  • response.formData() - 将响应解析为 FormData 对象
  • response.arrayBuffer() - 将响应解析为 ArrayBuffer

每个方法都返回一个 Promise,解析为相应格式的数据。

javascript
// 获取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);
});

检查响应状态

在处理响应之前,通常需要检查响应是否成功:

javascript
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() 方法接受第二个可选参数,是一个配置对象,可以自定义请求:

javascript
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));

常用配置选项

  1. method: 请求方法(GET、POST、PUT、DELETE 等)
  2. headers: 请求头对象
  3. body: 请求体数据(适用于 POST/PUT 等方法)
  4. mode: 请求模式(cors、no-cors、same-origin、navigate)
  5. credentials: 是否包含凭证(omit、same-origin、include)
  6. cache: 缓存模式(default、no-store、reload、no-cache、force-cache、only-if-cached)

发送不同类型的请求

GET 请求(获取数据)

GET 请求是默认的请求方法,用于从服务器获取数据:

javascript
fetch('https://api.example.com/users')
.then(response => response.json())
.then(users => console.log(users));

POST 请求(创建数据)

POST 请求用于向服务器发送数据,通常用于创建新资源:

javascript
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 请求用于更新服务器上的现有资源:

javascript
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 请求用于删除服务器上的资源:

javascript
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 的代码更加清晰易读:

javascript
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 时,需要注意两种类型的错误:

  1. 网络错误:如果请求不能完成(如网络断开),fetch 会抛出错误,触发 catch 子句
  2. HTTP 错误:如果服务器返回错误状态码(如 404、500),fetch 不会自动抛出错误,需要检查 response.okresponse.status
javascript
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 请求:

javascript
// 创建一个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 构建简单天气应用的示例:

javascript
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结构可能如下:

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 应用程序的基础技能之一。

练习与挑战

  1. 基础练习:使用 Fetch API 获取一个公开 API(如 JSONPlaceholder)的数据,并在页面上显示
  2. 中级练习:创建一个表单,使用 Fetch 发送 POST 请求,并处理服务器响应
  3. 高级挑战:构建一个小型应用,结合 GET、POST、PUT 和 DELETE 请求,实现对资源的完整 CRUD 操作

额外资源

提示

记住,尽管 Fetch API 在现代浏览器中得到广泛支持,但在支持旧浏览器(特别是 IE)的项目中,你可能需要使用 polyfill 或考虑使用 Axios 等替代库。