Skip to content

HTTP、Fetch 与响应契约 ​

Fetch 的最小闭环是请求、检查响应、解析数据和处理失败。fetch 只在网络层失败时 reject,HTTP 404/500 仍会 resolve,因此必须显式检查 response.ok。

js
async function loadJson(url, signal) {
  const response = await fetch(url, { signal, headers: { Accept: 'application/json' } })
  if (!response.ok) throw new Error(`HTTP ${response.status}`)
  return response.json()
}

const controller = new AbortController()
console.log(await loadJson('data:application/json,%7B%22items%22%3A%5B1%2C2%5D%7D', controller.signal))

function classify(response) {
  if (!response.ok) return { state: 'error', message: `HTTP ${response.status}` }
  return { state: 'success' }
}
console.log(classify({ ok: false, status: 404 })) // { state: 'error', message: 'HTTP 404' }

先运行成功分支,再用 classify 验证 404/500 的 UI 状态;data: URL 只能模拟成功的 JSON 响应,真实状态码、超时和断网需要本地 HTTP 服务或浏览器 DevTools 进行第二次实验。

把响应校验和业务转换分开,才能区分网络断开、HTTP 错误和 JSON 结构错误。请求状态至少区分 idle、pending、success、empty、error;不要用一个 null 同时表示未加载和空结果。

练习 ​

为列表请求设计 404、500、错误 JSON 和空数组四条输入,写出用户可见状态和重试策略。

核心机制与实现 ​

网络请求有请求生命周期、缓存和取消;本地存储有同步 API、配额、版本迁移和跨标签页一致性。

围绕“HTTP、Fetch 与响应契约”先写出输入 → 中间状态 → 可观察结果,再实现最小闭环。不要把事件监听、异步请求、DOM 读取或 store 写入混在一个函数里;每个副作用都要有创建、完成、取消和清理路径。

js
const controller = new AbortController()
const request = fetch('/api/items', { signal: controller.signal })
setTimeout(() => controller.abort(), 500)
await request

逐步运行:先只验证成功路径,再改变一个输入;记录时间顺序、对象身份、错误类型和最终可见状态。若环境不支持某个浏览器 API,要把静态协议验证和真实浏览器验证分开记录。

失败边界与变体 ​

  • 输入为空、重复、过期或非法时,不应静默覆盖有效状态。
  • 组件卸载、路由离开、标签页关闭或请求取消时,资源必须停止写入。
  • 跨文档、Shadow DOM、Worker、SSR 或多标签页会改变可见边界,不能沿用单页面直觉。
  • 需要持久化时记录 schema 版本和迁移失败策略;需要全局状态时先证明局部状态不足。

可运行实验与练习 ​

分别测试成功、HTTP 错误、网络错误、超时取消、重复提交和旧数据迁移;记录请求状态与存储版本。

练习要求:实现一个最小版本,补一个失败测试,再给出一个替代方案及其适用条件。答案应包括实际输入序列、观察结果、修复原因和未覆盖的浏览器差异。

查看本节答案

下一步 ​

完成练习后打开本章答案,再回到网络与存储课程总览。

用心记录每一步成长