本文是 JavaScript Fetch API + HTTP 网络请求 权威教程,涵盖 GET/POST/PUT/DELETE、响应处理、错误捕获、取消请求、async/await 最佳实践。


一、开篇:Fetch 是什么?

JavaScript 如何从服务器获取数据?如何加载用户信息、提交表单、拉取最新列表?答案就是:Fetch API——JS 现代网络请求标准。

// 最基础的 Fetch 请求
const response = await fetch('https://api.example.com/users/1')
const user = await response.json()
console.log(user.name) // "Alice"

学习本文前你需要掌握:Promise、async/await(Fetch 基于 Promise 实现)。


二、HTTP 基础(必须懂)

什么是 HTTP?

HTTP(超文本传输协议)是 Web 数据通信的基础。它是客户端 ↔ 服务器之间的消息格式与传输规则。

HTTP 与语言无关,Python/Java/JS 都使用它。

请求 - 响应模型(餐厅类比)

  1. 你(客户端) 点餐 → 请求(Request)
  2. 服务员(网络) 传给厨房
  3. 厨房(服务器) 处理
  4. 服务员把菜给你 → 响应(Response)

三、5 个最常用 HTTP 方法

方法 作用 类比
GET 获取数据 看菜单
POST 创建数据 下单
PUT 整体替换数据 换菜
PATCH 部分更新数据 加配料
DELETE 删除数据 取消订单
// GET
fetch('/api/users/123')

// POST
fetch('/api/users', {
  method: 'POST',
  body: JSON.stringify({ name: 'Alice' }),
  headers: { 'Content-Type': 'application/json' }
})

四、HTTP 状态码(速记)

  • 2xx(成功):200 OK、201 创建成功、204 无内容
  • 3xx(重定向):301/302/304 缓存
  • 4xx(客户端错):400 参数错、401 未登录、403 无权、404 不存在
  • 5xx(服务端错):500 服务器崩溃、503 服务不可用

口诀:2xx 成了、3xx 挪了、4xx 你错了、5xx 他炸了。


五、Fetch API 是什么?

JS 原生现代网络请求 API,替代老旧的 XMLHttpRequest(XHR)

优点:

  • Promise 化
  • 支持 async/await
  • 流式响应
  • 标准化 Request/Response
  • 现代浏览器全支持

六、Fetch 基础使用

1)GET 请求(最简)

async function getUsers() {
  const res = await fetch('/api/users')
  const data = await res.json()
  return data
}

2)POST 请求(提交 JSON)

async function createUser(user) {
  const res = await fetch('/api/users', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(user)
  })
  return res.json()
}

3)Response 对象常用属性

res.status      // 200 / 404 / 500
res.ok         // 200~299 → true
res.statusText // "OK" / "Not Found"
res.headers    // 响应头
res.url        // 最终URL

4)解析响应体(都是 Promise)

await res.json()       // JSON
await res.text()       // 纯文本
await res.blob()       // 文件/二进制
await res.formData()   // 表单
await res.arrayBuffer() // 缓冲区

⚠️ 重要响应体只能读一次,多次读取需用 res.clone()


七、Fetch 最容易犯的错误(99% 人中招)

❌ 错误:以为 try/catch 能捕获 404/500

Fetch 只有网络错误才会 reject!404、500 属于成功的响应,不会进 catch。

// ❌ 错误:404/500 不会被捕获
try {
  const res = await fetch('/api/bad')
  const data = await res.json()
} catch (err) {
  // 只有断网/CORS/超时才会进来
}

✅ 正确:必须判断 res.ok

const res = await fetch(url)
if (!res.ok) {
  throw new Error(`HTTP 错误 ${res.status}`)
}
const data = await res.json()

八、超实用封装:fetchJSON

async function fetchJSON(url, options = {}) {
  const res = await fetch(url, {
    headers: { 'Content-Type': 'application/json', ...options.headers },
    ...options
  })

  if (!res.ok) {
    const err = new Error(`HTTP ${res.status}`)
    err.status = res.status
    throw err
  }

  return res.status === 204 ? null : res.json()
}

九、并行请求(提速关键)

// ✅ 并行(快)
const [users, posts] = await Promise.all([
  fetch('/api/users').then(r => r.json()),
  fetch('/api/posts').then(r => r.json())
])

十、取消请求:AbortController

用于:

  • 超时取消
  • 页面离开取消
  • 搜索防抖(取消上一次请求)

使用步骤

  1. 创建控制器
  2. 传入 signal
  3. 调用 abort ()
const controller = new AbortController()

fetch('/api/slow', { signal: controller.signal })
  .catch(err => {
    if (err.name === 'AbortError') console.log('已取消')
  })

// 5秒后取消
setTimeout(() => controller.abort(), 5000)

搜索防抖(高频实战)

let prevController = null
async function search(q) {
  if (prevController) prevController.abort()
  const ctrl = new AbortController()
  prevController = ctrl

  const res = await fetch(`/api/search?q=${q}`, { signal: ctrl.signal })
  return res.json()
}

十一、超时封装(必备)

async function fetchWithTimeout(url, opts = {}, ms = 5000) {
  const ctrl = new AbortController()
  const timer = setTimeout(() => ctrl.abort(), ms)

  try {
    const res = await fetch(url, { ...opts, signal: ctrl.signal })
    clearTimeout(timer)
    return res
  } catch (err) {
    clearTimeout(timer)
    throw err
  }
}

十二、核心总结(必背)

  1. Fetch 是现代 Promise 化请求 API
  2. 默认 GET
  3. 必须判断 res.ok 才能捕获 4xx/5xx
  4. 响应体要 await 解析
  5. 网络错误才进 catch
  6. AbortController 用于取消请求
  7. Promise.all 做并行请求
  8. 永远不要手动拼接 URL 参数,用 URLSearchParams

构建带加载状态的请求模式(真实项目必备)

在实际应用里,你通常需要同时管理 加载中 / 成功 / 失败 三种状态:

async function fetchWithState(url) {
  const state = {
    data: null,
    loading: true,
    error: null
  }

  try {
    const response = await fetch(url)
    if (!response.ok) throw new Error(`HTTP ${response.status}`)
    state.data = await response.json()
  } catch (err) {
    state.error = err.message
  } finally {
    state.loading = false
  }

  return state
}

如何取消请求(AbortController)

适用场景

  • 请求超时
  • 用户离开页面
  • 搜索框连续输入(取消上一次请求)
  • 组件卸载(React/Vue)

完整工作流程

  1. 创建 AbortController 实例
  2. controller.signal 传给 fetch
  3. 调用 controller.abort() 取消请求
  4. catch 会捕获 AbortError

完整代码示例

const controller = new AbortController()

fetch("/api/data", { signal: controller.signal })
  .then(res => res.json())
  .catch(err => {
    if (err.name === "AbortError") {
      console.log("请求已取消")
    }
  })

// 手动取消
controller.abort()

超时封装

async function fetchWithTimeout(url, options = {}, timeout = 5000) {
  const controller = new AbortController()
  const timer = setTimeout(() => controller.abort(), timeout)

  try {
    const res = await fetch(url, {
      ...options,
      signal: controller.signal
    })
    clearTimeout(timer)
    return res
  } catch (err) {
    clearTimeout(timer)
    if (err.name === "AbortError") {
      throw new Error(`请求超时 ${timeout}ms`)
    }
    throw err
  }
}

搜索输入防抖(完整版)

let currentController = null

async function searchUsers(keyword) {
  // 取消上一次请求
  if (currentController) currentController.abort()

  const ctrl = new AbortController()
  currentController = ctrl

  try {
    const res = await fetch(`/api/search?q=${keyword}`, {
      signal: ctrl.signal
    })
    if (!res.ok) throw new Error("请求失败")
    return await res.json()
  } catch (err) {
    if (err.name === "AbortError") return null
    throw err
  }
}

知识测验(完整版)

Q1:网络错误与 HTTP 错误的区别

网络错误:断网、DNS 失败、CORS、连接失败 → Promise 拒绝(进入 catch)HTTP 错误:404/500 → Promise 已完成,必须判断 response.ok

Q2:为什么 response.json() 返回 Promise?

因为响应体是流(stream),需要异步完整读取后才能解析成 JSON。

Q3:POST 发送 JSON 必须做哪三件事?

  1. method: 'POST'
  2. headers: { 'Content-Type': 'application/json' }
  3. body: JSON.stringify(data)

Q4:response.ok 是什么意思?

状态码 200~299true,否则 false

Q5:如何取消 fetch?

使用 AbortController,传入 signal,调用 abort()

Q6:如何并行发送多个请求?

使用 Promise.all(),并发执行,速度远快于串行。


常见问题 FAQ(完整版)

Q:Fetch API 是什么?

JS 原生现代 HTTP 请求接口,基于 Promise,替代 XMLHttpRequest,所有现代浏览器与 Node.js 18+ 支持。

Q:fetch 与 XMLHttpRequest 有什么区别?

  • fetch:Promise、简洁、支持流、现代标准
  • XHR:回调、繁琐、老项目兼容

Q:为什么 fetch 对 404/500 不抛错?

因为 fetch 只认网络失败为错误。404/500 属于服务器正常响应,不算网络失败,必须手动判断 ok

Q:如何取消 fetch?

使用 AbortController

Q:GET 和 POST 到底区别是什么?

  • GET:获取数据,参数在 URL,可缓存
  • POST:提交数据,参数在 body,不默认缓存

新概念 + 类似概念(完整汇总)

1. HTTP 核心概念

  • HTTP 请求 - 响应模型同类:客户端 / 服务端通信、请求应答模式
  • HTTP 方法(GET/POST/PUT/PATCH/DELETE)同类:RESTful API、增删改查操作
  • HTTP 状态码(2xx/3xx/4xx/5xx)同类:响应状态、业务状态码、接口错误码
  • 请求头 / 响应头(Headers)同类:元信息、权限传递、内容类型

2. Fetch API 核心

  • Fetch API同类:网络请求、AJAX、HttpClient
  • Response 对象同类:响应封装、接口结果
  • 请求体流(ReadableStream)同类:流式响应、分段加载、文件上传

3. 异步与控制

  • AbortController同类:取消请求、中断请求、防抖
  • AbortSignal同类:取消信号、中断信号
  • AbortError同类:取消异常、请求终止

4. 工程模式

  • 并行请求(Promise.all)同类:并发加载、批量请求
  • 超时控制同类:请求超时、熔断、保护机制
  • 防抖搜索同类:输入优化、避免重复请求
  • 加载状态管理同类:异步状态、UI 状态、请求生命周期

5. 对比概念

  • XMLHttpRequest(XHR)同类:旧式 AJAX、传统请求
  • axios(同类库)同类:HTTP 客户端、请求库
  • JSON 序列化同类:数据格式、字符串化

 

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐