MDN项目详解:现代Web请求利器Fetch API使用指南
什么是Fetch API
Fetch API是现代浏览器提供的用于发起网络请求的JavaScript接口,它取代了传统的XMLHttpRequest(XHR),采用基于Promise的设计模式,完美契合现代Web开发需求。与XHR相比,Fetch API具有以下优势:
- 基于Promise的异步处理机制,避免了回调地狱
- 天然支持CORS(跨域资源共享)
- 与Service Worker无缝集成
- 提供更简洁直观的API设计
基础用法示例
让我们从一个最简单的Fetch示例开始:
async function fetchData() {
const url = "https://api.example.com/data";
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP错误! 状态码: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error("请求失败:", error);
}
}
这个示例展示了Fetch API的基本工作流程:
- 调用
fetch()
发起请求 - 检查响应状态
- 解析响应体为JSON格式
- 处理可能的错误
配置请求参数
Fetch API提供了丰富的配置选项,让我们可以定制各种类型的HTTP请求。
请求方法设置
默认情况下,fetch使用GET方法,但我们可以通过method选项指定其他HTTP方法:
const response = await fetch("https://api.example.com/resource", {
method: "POST", // 可以是GET、POST、PUT、DELETE等
});
请求头设置
我们可以通过headers选项设置自定义请求头:
const response = await fetch(url, {
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer token123"
}
});
或者使用Headers对象:
const headers = new Headers();
headers.append("Content-Type", "application/json");
const response = await fetch(url, { headers });
请求体设置
对于POST、PUT等需要发送数据的请求,我们可以通过body选项设置请求体:
const response = await fetch(url, {
method: "POST",
body: JSON.stringify({ key: "value" }),
headers: { "Content-Type": "application/json" }
});
支持多种数据类型作为请求体:
- 字符串
- FormData对象(适合文件上传)
- Blob/BufferSource
- URLSearchParams(适合表单编码数据)
- ReadableStream
处理响应
检查响应状态
Fetch API不会因为HTTP错误状态码(如404或500)而拒绝Promise,我们需要手动检查:
if (!response.ok) {
throw new Error(`请求失败,状态码: ${response.status}`);
}
解析响应体
Response对象提供了多种方法来解析响应体:
const text = await response.text(); // 解析为文本
const json = await response.json(); // 解析为JSON
const blob = await response.blob(); // 解析为Blob对象
const formData = await response.formData(); // 解析为FormData
处理响应头
我们可以通过headers属性访问响应头:
const contentType = response.headers.get("content-type");
const allHeaders = Object.fromEntries(response.headers.entries());
高级特性
跨域请求处理
Fetch API默认使用CORS机制处理跨域请求:
// 允许跨域请求(默认)
const response = await fetch("https://other-domain.com/data");
// 禁止跨域请求
const response = await fetch("https://other-domain.com/data", {
mode: "same-origin"
});
// 简单跨域请求(受限)
const response = await fetch("https://other-domain.com/data", {
mode: "no-cors"
});
凭据控制
控制是否发送cookie等凭据:
// 不发送凭据(默认)
const response = await fetch(url, { credentials: "omit" });
// 同源请求发送凭据
const response = await fetch(url, { credentials: "same-origin" });
// 总是发送凭据(跨域时需服务器配合)
const response = await fetch(url, { credentials: "include" });
请求取消
通过AbortController实现请求取消:
const controller = new AbortController();
// 设置超时自动取消
const timeoutId = setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch(url, {
signal: controller.signal
});
clearTimeout(timeoutId);
// 处理响应
} catch (error) {
if (error.name === "AbortError") {
console.log("请求被取消");
} else {
console.error("请求失败:", error);
}
}
最佳实践
- 错误处理:始终处理可能的错误,包括网络错误和HTTP错误状态
- 超时控制:结合AbortController实现请求超时
- 请求重用:对于需要多次使用的请求,使用Request对象
- 响应类型检查:在解析响应体前检查Content-Type
- 性能优化:对于大文件下载,使用流式处理
常见问题解答
Q: Fetch和XHR有什么区别? A: Fetch基于Promise设计,API更简洁,天然支持流式数据处理,但XHR支持进度事件而Fetch不支持。
Q: 为什么404响应不会触发catch? A: Fetch只在网络故障时拒绝Promise,HTTP错误状态需要通过response.ok或response.status检查。
Q: 如何上传文件? A: 使用FormData对象:
const formData = new FormData();
formData.append("file", fileInput.files[0]);
const response = await fetch("/upload", {
method: "POST",
body: formData
});
Q: 如何发送URL编码的表单数据? A: 使用URLSearchParams:
const params = new URLSearchParams();
params.append("key1", "value1");
params.append("key2", "value2");
const response = await fetch("/submit", {
method: "POST",
body: params,
headers: { "Content-Type": "application/x-www-form-urlencoded" }
});
通过本文,您应该已经掌握了Fetch API的核心用法和最佳实践。Fetch API作为现代Web开发的标配,合理使用可以大大简化网络请求相关的代码,提升应用性能和开发效率。