为什么用 fetch 发送 PATCH 请求返回 404 / 500,代码却没有进入 catch?正确的错误处理应该怎么写?

这是 fetch 最容易踩的坑之一。

原因:fetch 只在「网络层失败」时才 reject

fetch 的设计是:只有在网络请求本身失败(断网、DNS 解析失败、CORS 被拦截、请求被 abort)时才会 reject 并进入 catch。

而 HTTP 状态码 404 / 500 属于「请求成功到达服务器并拿到了响应」,只是响应状态码表示业务失败——这种情况 fetch 认为请求是「成功完成」的,会正常 resolve,Promise 进入 then,而不会进入 catch。

// ❌ 错误写法:以为 404/500 会进 catch
fetch('/api/user', { method: 'PATCH', body: JSON.stringify(data) })
  .then(res => {
    // 404/500 也会走到这里!
    return res.json()
  })
  .catch(err => {
    // 只有网络错误才进这里
  })

正确做法:手动检查响应状态

fetch('/api/user', { method: 'PATCH', body: JSON.stringify(data) })
  .then(res => {
    if (!res.ok) {
      // res.ok 为 false 表示状态码 >= 400
      throw new Error('请求失败:' + res.status + ' ' + res.statusText)
    }
    return res.json()
  })
  .then(data => { /* 业务成功 */ })
  .catch(err => { /* 网络错误 + 主动抛出的 HTTP 错误都到这里 */ })

// 或更推荐的 async/await 写法
async function patchUser(data) {
  const res = await fetch('/api/user', {
    method: 'PATCH',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  })
  if (!res.ok) {
    throw new Error('HTTP ' + res.status)
  }
  return res.json()
}

常见误区

同分类其他题目