博主头像
<CodeEra />

心存敬畏 行有所止

深入理解 Fetch API 的工作原理与错误处理

核心概念

Fetch API 提供了一种现代、基于 Promise 的方式来进行网络请求。它的设计遵循 分离关注点 原则,分为 获取响应解析数据 两个主要阶段。

1. 基本用法

fetch(url)
  .then(response => response.json())  // 解析 Response 为 JSON
  .then(data => console.log(data))    // 处理解析后的数据
  .catch(error => console.error(error)); // 捕获整个链的错误
  • fetch() 返回一个 Promise,解析为 Response 对象。
  • 第一个 .then() 处理 Response,检查状态码(response.ok),并调用 .json() / .text() / .blob() 解析数据。
  • 第二个 .then() 处理解析后的数据(如 JSON 对象)。
  • .catch() 捕获整个链中的任何错误(网络错误、HTTP 错误、解析错误等)。

2. 为什么需要两个 .then()

阶段 1:获取原始响应(Response)

  • fetch 返回的 Promise 解析为 Response 对象,包含 HTTP 状态、headers 等信息。
  • 必须手动检查 response.okresponse.status,因为 HTTP 错误(404、500)不会自动触发 .catch()

阶段 2:解析数据

  • response.json() / .text() / .blob() 返回新的 Promise,因为解析可能是异步的。
  • 第二个 .then() 接收解析后的数据(如 JSON 对象)。

类比:拆快递

  1. 签收快递(第一个 .then():检查包裹是否完好(response.ok)。
  2. 拆包裹(.json():解析内容(返回新的 Promise)。
  3. 使用商品(第二个 .then():处理实际数据。

3. 错误处理机制

.catch() 捕获哪些错误?

  • 网络错误(如无法连接服务器、CORS 问题)。
  • HTTP 错误(需手动检查 response.okthrow)。
  • 解析错误(如无效 JSON)。
  • 业务逻辑错误(在 .then() 中手动抛出)。

如何区分不同错误?

.catch(error => {
  if (error instanceof TypeError) {
    console.error("网络错误或无效 URL");
  } else if (error instanceof SyntaxError) {
    console.error("JSON 解析失败");
  } else {
    console.error("其他错误", error);
  }
});

最佳实践

  1. 始终检查 response.ok

    if (!response.ok) throw new Error(`HTTP ${response.status}`);
  2. 拆分错误处理(如需精细控制):

    fetch(url)
      .then(handleResponse)  // 单独处理 HTTP 错误
      .then(handleData)      // 处理数据
      .catch(handleNetworkError); // 捕获网络错误

4. 高级技巧

取消请求(AbortController)

const controller = new AbortController();
fetch(url, { signal: controller.signal })
  .then(response => response.json())
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log("请求被取消");
    }
  });

// 取消请求
controller.abort();

POST 请求示例

fetch(url, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ key: 'value' }),
});

总结

  1. fetch 返回 Promise<Response>,需用 .then() 处理。
  2. 两个 .then() 分工明确

    • 第一个处理 Response(HTTP 层面)。
    • 第二个处理解析后的数据(业务层面)。
  3. .catch() 捕获整个链的错误,需手动检查 HTTP 错误。
  4. 灵活运用 AbortControllerheadersbody 可满足复杂需求
发表新评论