人人都会AI编程

16.2 Fetch API:Promise 化的现代请求方案

更新时间:2026-07-11

Fetch API 是浏览器原生提供的、基于 Promise 的现代网络请求接口。相比老旧的 XMLHttpRequest(XHR),它将请求与响应抽象为更清晰的 Request 和 Response 对象,并使用 Promise 管理流程,避免了回调嵌套,代码可读性大幅提升。

基本用法

最基础的 GET 请求只需要一行:

fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(err => console.error('请求失败', err));

如果需要 POST JSON 数据,可以配置第二个参数:

fetch('https://api.example.com/submit', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: '张三', age: 25 })
})
  .then(response => response.json())
  .then(data => console.log('成功', data))
  .catch(err => console.error('失败', err));

核心配置项

fetch(input, init) 的第二个参数 init 是一个配置对象,常用选项如下:

  • method:请求方法,如 GETPOSTPUTDELETE,默认 GET
  • headers:请求头对象,既可以是普通字面量,也可以通过 new Headers() 构建。
  • body:请求体,用于 POST/PUT 等,可以是字符串、FormData、Blob、URLSearchParams 等。
  • mode:跨域模式,如 cors(默认,允许跨域但需服务器配合)、no-corssame-origin
  • credentials:是否携带 Cookie,include(携带)、same-origin(默认,同源携带)、omit
  • signal:关联 AbortController,用于取消请求。

与 XHR 的核心差异

| 特性 | XMLHttpRequest | Fetch API |
|------|---------------|-----------|
| 异步模型 | 基于事件回调 (onloadonerror) | 基于 Promise,支持链式调用与 async/await |
| 请求取消 | xhr.abort() | 通过 AbortController.signal 传入 |
| 进度监听 | 支持 xhr.upload.onprogress | 原生不支持上传进度(需借助流式接口) |
| 接收流数据 | 不支持 | 支持 response.body 可读流,适合大文件下载 |
| 超时设置 | 内置 xhr.timeout | 无内置超时,需自行通过 AbortControllerPromise.race 模拟 |
| 跨域 Cookie | 默认携带同源 Cookie | 默认不携带,需显式设置 credentials: 'include' |

使用 async/await 后的 Fetch 代码与同步写法几乎一致:

async function getUser() {
  const response = await fetch('/api/user');
  if (!response.ok) throw new Error('接口返回错误');
  return response.json();
}

不可忽视的局限性

  1. 只对网络错误 reject

HTTP 状态码 4xx、5xx 不会让 fetch 走到 catch,必须手动检查 response.okresponse.status。这是很多初学者的坑点。

  1. 不支持超时控制

原生的 fetch 没有超时选项,必须通过 AbortController 配合 setTimeout 来实现:

   const controller = new AbortController();
   setTimeout(() => controller.abort(), 5000);
   fetch('/api/data', { signal: controller.signal })
     .catch(err => { if (err.name === 'AbortError') console.log('请求超时取消'); });
   
  1. 无法监听上传进度

文件上传时如果需要进度条,fetch 目前无法直接提供 upload progress,只能退回到 XHR 或使用 Service Worker 流处理(不常用)。

  1. 默认不携带 Cookie

出于安全考虑,同源请求也需要显式指定 credentials: 'include' 才会发送 Cookie,否则响应中的 Set-Cookie 可能被忽略。

  1. 兼容性中等

Fetch API 已在所有现代浏览器中落地,但 IE 完全不支持(需要使用 polyfill),部分老版本 Android WebView 也有缺失。

实用建议

  • 在实际项目中,常常对 fetch 做一层简易封装,统一处理错误、添加超时、自动 JSON 解析、基础鉴权等。
  • 对于需要上传进度、兼容旧浏览器或需要更复杂功能的场景,推荐使用经过社区检验的库(如 Axios),它们内部封装了大量细节,让开发更高效稳健。

Fetch API 在现代 Web 开发中已经是基础能力,理解它的特性与局限,能帮助你写出更健壮的网络请求代码,也为理解 Axios 等上层封装打下基础。