讲解

fetch 是浏览器内置的现代网络请求 API,基于 Promise,取代了老旧的 XMLHttpRequest。最基本的用法是 const response = await fetch(url):它只完成「发出请求并拿到响应头」这一步,读取响应体要再调 response.json()(解析 JSON)或 response.text()(读文本),这些方法同样返回 Promise。response.ok(状态码 200-299)和 response.status 用来判断请求是否成功。

fetch 有个著名的反直觉设计:只有网络层失败(断网、DNS 失败、跨域被拦)才会 reject;HTTP 错误状态(404、500)照样 resolve——你必须自己检查 response.ok,否则 404 的响应体可能被当成功数据解析。POST 等带数据的请求要配置第二个参数:method、headers('Content-Type': 'application/json')、body(JSON.stringify 后的字符串)。

生产级的 fetch 还要处理两件事:超时与取消——用 AbortController,把 controller.signal 传给 fetch,需要取消时调 controller.abort(),fetch 会以 AbortError 拒绝;配合 setTimeout 就是超时控制。错误处理的完整姿势:try/catch 接住网络错误与中止,if (!response.ok) 处理 HTTP 错误,json 解析失败再兜底一层。

示例

fetch 依赖网络环境,无法在本页沙盒运行,以下代码请在浏览器控制台体验(jsonplaceholder 是公开的测试接口):

// GET:获取并解析 JSON
async function loadPost() {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
    if (!response.ok) {
      throw new Error('HTTP 错误:' + response.status); // fetch 不会因 404/500 自动 reject
    }
    const post = await response.json();
    console.log('标题:', post.title);
    return post;
  } catch (err) {
    console.error('请求失败:', err.message);
  }
}
// POST:提交 JSON 数据
async function createPost() {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ title: '你好', body: '正文内容', userId: 1 }),
  });
  if (!response.ok) throw new Error('提交失败:' + response.status);
  return response.json();
}
// 超时与取消:AbortController
async function fetchWithTimeout(url, timeoutMs = 5000) {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);
  try {
    const response = await fetch(url, { signal: controller.signal });
    if (!response.ok) throw new Error('HTTP ' + response.status);
    return await response.json();
  } catch (err) {
    if (err.name === 'AbortError') throw new Error('请求超时');
    throw err;
  } finally {
    clearTimeout(timer);
  }
}

常见坑

  • 以为 404 会进 catch:fetch 只在网络故障时 reject,HTTP 错误要检查 response.ok 或 response.status,这是新手第一大坑。
  • 忘记 await response.json():直接 console.log(response) 打印的是响应对象不是数据;response.json() 也是异步的。
  • 响应体读两次:response.json() 之后不能再 response.text(),body 只能消费一次,报 "body used already"。
  • 跨域报错无从下手:fetch 默认受同源策略约束,跨域需要服务端配 CORS 响应头,前端改 mode 绕不过去——这是服务端配置问题。

小结

fetch 发请求、response.json() 取数据;HTTP 错误不 reject,自查 response.ok;AbortController 管超时取消。下一章开始操作网页本身:DOM 基础。