Fetch API是现代的网络请求接口。
// 基本用法
fetch("/api/data")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
// 使用async/await
async function fetchData() {
try {
const response = await fetch("/api/data");
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
// fetch返回Promise,解析为Response对象
const response = await fetch("/api/data");
console.log(response.ok); // 是否成功(status 200-299)
console.log(response.status); // HTTP状态码
console.log(response.statusText);// 状态文本
console.log(response.headers); // 响应头
console.log(response.url); // 最终URL
console.log(response.redirected);// 是否重定向
console.log(response.type); // 类型:basic, cors, opaque
创建和配置请求。
// 使用Request对象
const request = new Request("/api/data", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
});
fetch(request)
.then(response => response.json())
.then(data => console.log(data));
// 直接传递配置
fetch("/api/data", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
});
const request = new Request("/api/data", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ name: "东巴文" }),
mode: "cors",
credentials: "include",
cache: "no-cache",
redirect: "follow",
referrer: "no-referrer"
});
console.log(request.url); // URL
console.log(request.method); // 方法
console.log(request.headers); // 请求头
console.log(request.body); // 请求体
console.log(request.mode); // 模式
console.log(request.credentials);// 凭证
console.log(request.cache); // 缓存模式
console.log(request.redirect); // 重定向模式
处理服务器响应。
const response = await fetch("/api/data");
// 状态信息
console.log(response.status); // 200
console.log(response.statusText); // "OK"
console.log(response.ok); // true
// 响应头
console.log(response.headers.get("Content-Type"));
console.log(response.headers.get("Content-Length"));
// 遍历响应头
for (const [key, value] of response.headers) {
console.log(key, value);
}
const response = await fetch("/api/data");
// JSON
const json = await response.json();
// 文本
const text = await response.text();
// Blob
const blob = await response.blob();
// ArrayBuffer
const buffer = await response.arrayBuffer();
// FormData
const formData = await response.formData();
// 注意:响应体只能读取一次
// const json = await response.json();
// const text = await response.text(); // 错误:已读取
const response = await fetch("/api/data");
// 克隆响应
const cloned = response.clone();
// 可以分别读取
const json = await response.json();
const text = await cloned.text();
管理请求和响应头。
// 创建Headers对象
const headers = new Headers();
headers.append("Content-Type", "application/json");
headers.append("Authorization", "Bearer token");
// 使用对象初始化
const headers2 = new Headers({
"Content-Type": "application/json",
"Authorization": "Bearer token"
});
// 直接使用对象
fetch("/api/data", {
headers: {
"Content-Type": "application/json"
}
});
const headers = new Headers();
// 添加
headers.append("X-Custom", "value");
// 设置(覆盖)
headers.set("Content-Type", "application/json");
// 获取
console.log(headers.get("Content-Type"));
// 检查
console.log(headers.has("Authorization"));
// 删除
headers.delete("X-Custom");
// 遍历
for (const [key, value] of headers) {
console.log(key, value);
}
// 转换为对象
const obj = Object.fromEntries(headers);
配置fetch请求选项。
// GET请求
fetch("/api/data");
// POST请求
fetch("/api/users", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "东巴文",
email: "info@db-w.cn"
})
});
// PUT请求
fetch("/api/users/1", {
method: "PUT",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "新名称"
})
});
// DELETE请求
fetch("/api/users/1", {
method: "DELETE"
});
// cors: 跨域请求(默认)
fetch("https://api.db-w.cn/data", {
mode: "cors"
});
// no-cors: 不发送CORS请求
fetch("https://other.com/data", {
mode: "no-cors"
});
// same-origin: 仅同源
fetch("/api/data", {
mode: "same-origin"
});
// omit: 不发送Cookie
fetch("/api/data", {
credentials: "omit"
});
// same-origin: 同源发送Cookie(默认)
fetch("/api/data", {
credentials: "same-origin"
});
// include: 始终发送Cookie
fetch("https://api.db-w.cn/data", {
credentials: "include"
});
// default: 使用缓存,必要时更新
fetch("/api/data", { cache: "default" });
// no-store: 不使用缓存
fetch("/api/data", { cache: "no-store" });
// reload: 重新加载
fetch("/api/data", { cache: "reload" });
// no-cache: 使用缓存前验证
fetch("/api/data", { cache: "no-cache" });
// force-cache: 强制使用缓存
fetch("/api/data", { cache: "force-cache" });
// only-if-cached: 仅使用缓存
fetch("/api/data", { cache: "only-if-cached" });
处理各种响应类型。
async function fetchJSON(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
// 使用
const data = await fetchJSON("/api/data");
console.log(data);
async function fetchText(url) {
const response = await fetch(url);
return response.text();
}
const html = await fetchText("/page.html");
document.getElementById("content").innerHTML = html;
// 下载文件
async function downloadFile(url, filename) {
const response = await fetch(url);
const blob = await response.blob();
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;
link.click();
URL.revokeObjectURL(link.href);
}
// 显示图片
async function loadImage(url) {
const response = await fetch(url);
const blob = await response.blob();
const img = document.createElement("img");
img.src = URL.createObjectURL(blob);
document.body.appendChild(img);
}
fetch返回Promise。
fetch("/api/user/1")
.then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
})
.then(user => {
console.log(user);
return fetch(`/api/posts/${user.id}`);
})
.then(response => response.json())
.then(posts => {
console.log(posts);
})
.catch(error => {
console.error("错误:", error);
});
// 并行请求
const [users, posts, comments] = await Promise.all([
fetch("/api/users").then(r => r.json()),
fetch("/api/posts").then(r => r.json()),
fetch("/api/comments").then(r => r.json())
]);
正确处理fetch错误。
// fetch不会因HTTP错误状态而reject
fetch("/api/not-found")
.then(response => {
console.log(response.status); // 404
console.log(response.ok); // false
// Promise仍然是fulfilled
});
// 需要手动检查
async function fetchWithError(url) {
const response = await fetch(url);
if (!response.ok) {
const error = new Error(`HTTP ${response.status}`);
error.response = response;
throw error;
}
return response.json();
}
// 网络错误会reject
fetch("https://nonexistent.domain")
.catch(error => {
console.error("网络错误:", error);
});
// 完整错误处理
async function safeFetch(url, options = {}) {
try {
const response = await fetch(url, options);
if (!response.ok) {
const error = new Error(`HTTP ${response.status}`);
error.response = response;
throw error;
}
return response;
} catch (error) {
if (error.name === "AbortError") {
console.error("请求被中止");
} else if (error.name === "TypeError") {
console.error("网络错误或URL无效");
}
throw error;
}
}
处理跨域请求。
// 跨域请求
fetch("https://api.db-w.cn/data", {
mode: "cors",
credentials: "include",
headers: {
"Content-Type": "application/json"
}
})
.then(response => response.json())
.then(data => console.log(data));
// 服务器需要设置:
// Access-Control-Allow-Origin: *
// Access-Control-Allow-Credentials: true
// Access-Control-Allow-Headers: Content-Type
// 简单请求:直接发送
fetch("https://api.db-w.cn/data", {
method: "GET"
});
// 预检请求:先发送OPTIONS
fetch("https://api.db-w.cn/data", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Custom-Header": "value"
},
body: JSON.stringify({ data: "东巴文" })
});
使用fetch上传文件。
const input = document.querySelector('input[type="file"]');
input.addEventListener("change", async function() {
const file = this.files[0];
const formData = new FormData();
formData.append("file", file);
const response = await fetch("/api/upload", {
method: "POST",
body: formData
});
const result = await response.json();
console.log(result);
});
// fetch不支持上传进度,需要使用XMLHttpRequest
function uploadWithProgress(file, onProgress) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = (e) => {
if (e.lengthComputable) {
onProgress(e.loaded / e.total * 100);
}
};
xhr.onload = () => {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.responseText));
} else {
reject(new Error(`HTTP ${xhr.status}`));
}
};
xhr.onerror = () => reject(new Error("网络错误"));
const formData = new FormData();
formData.append("file", file);
xhr.open("POST", "/api/upload");
xhr.send(formData);
});
}
// 使用
await uploadWithProgress(file, (percent) => {
console.log(`上传进度: ${percent.toFixed(0)}%`);
});
掌握了Fetch API后,让我们继续学习:
东巴文(db-w.cn) - 让编程学习更简单
🎯 东巴文寄语:Fetch API是现代JavaScript网络请求的标准方式,基于Promise设计,语法简洁优雅。在 db-w.cn,我们帮你掌握现代网络请求技术!