HTTP、Fetch 与取消请求
HTTP、Fetch 与取消请求 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。
学习目标
这一课用 fetch(浏览器内置的发请求接口)请求一个分页接口,把「成功、失败、脏数据、取消」四条路都走通,并对照 Network 面板理解请求头、状态码和取消在底层的样子。读完你应该能写出一个不白屏、不卡死、不串台的请求函数。
问题场景
课程列表翻到第 2 页要 2 秒,用户等不及点了第 3 页,又点了第 1 页。三个请求同时在飞,最后完成的却是第 2 页的——界面显示了第 2 页的数据,选中的却是第 1 页。这类「慢请求覆盖新请求」的串台,加上没检查 res.ok 导致的「把错误页当数据渲染」,是 fetch 代码最常见的两类事故。
核心解释
fetch 有两个和直觉不同的点,先立规矩:
- fetch 只在网络层失败时拒绝:404、500 也算「成功拿到了响应」,Promise 照样 resolve。所以拿到响应的第一件事是检查
res.ok(状态码 200–299 时为 true)。 - res.json() 也可能抛错:响应体不是 JSON(比如错误页的 HTML)时解析会抛异常,要放进同一个 try 里。
async function loadCourses(page, signal) {
const res = await fetch(`/api/courses?page=${page}`, { signal });
if (!res.ok) {
throw new Error(`请求失败:HTTP ${res.status}`); // 把状态码带给 catch
}
const data = await res.json(); // 可能抛错:返回的不是 JSON
if (!Array.isArray(data.items)) {
throw new Error('响应格式不符合预期'); // 运行时校验,别信接口
}
return data;
}
取消请求用 AbortController(浏览器提供的取消信号控制器):把它的 signal 传给 fetch,调用 abort() 时请求被中止,fetch 抛出特定错误:
const controller = new AbortController();
loadCourses(2, controller.signal).catch((err) => {
if (err.name === 'AbortError') return; // 主动取消,不算失败
showError(err.message);
});
controller.abort(); // 比如用户又点了别的页
示例拆解
修「翻页串台」的套路:每次新请求前,取消上一个还没完成的:
let controller = null;
async function goToPage(page) {
controller?.abort(); // 上一页还没回来?取消它
controller = new AbortController();
try {
const data = await loadCourses(page, controller.signal);
render(data); // 只有最后选中的页才可能走到这里
} catch (err) {
if (err.name !== 'AbortError') showError(err.message);
}
}
- 关键点:被 abort 的请求会拒绝并带上
AbortError,渲染代码不会执行——第 2 页的慢响应再也覆盖不了第 1 页。 - 到 Network 面板验证:被取消的请求 Status 列显示 canceled(红色),说明浏览器真的中止了它,而不是前端假装没看见。
- 请求头也在 Network 里看:Request Headers 里的 Accept 是浏览器自动加的;以后加登录态,就是在那里放 Authorization。
动手任务
本课没有在线实验,用真实浏览器完成(接口用公开测试服务 https://jsonplaceholder.typicode.com/posts?_page=1&_limit=5):
- 在控制台用 fetch 请求上面的地址,打印 res.status、res.ok 和 res.headers.get('content-type'),再到 Network 面板找到这条请求对照。
- 把地址改成不存在的
/postsXYZ,确认 fetch 不抛错而是返回 404;然后给你的请求函数加上 res.ok 检查。 - 快速连续改变
_page参数发三次请求,前两次都调用 abort 取消,观察 Network 面板里的 canceled 状态,确认只有最后一次的结果被渲染。
常见错误
- 不检查 res.ok:404 的响应体也可能被当数据渲染,报错信息完全看不懂;请求函数第一行就是
if (!res.ok) throw。 - catch 里不区分 AbortError:把用户主动取消当失败弹红字提示,用户一脸懵。
- 用防抖治串台:防抖只能少发请求,慢请求照样可能覆盖新请求;正确做法是 abort 旧请求。
- 信接口不信校验:接口哪天把 items 改成对象,页面直接白屏;边界处用
Array.isArray这类运行时检查兜底。
检查与复盘
完成下方检查题确认理解。自查清单:
- 能说清 fetch 什么时候拒绝、什么时候 resolve,以及 res.ok 的作用
- 写请求函数有固定骨架:检查状态 → 校验形状 → 带上下文抛错
- 能在 Network 面板找到 canceled 请求并解释 abort 的效果
参考资料
- MDN:fetch —— 参数、返回值与错误行为的正式定义
- MDN:AbortController —— 取消请求的标准做法
- MDN:HTTP 响应状态码 —— 状态码分类速查
读完这一课了?
标记完成后,工作台会安排接下来的学习。