HTTP 状态码是客户端与服务端沟通的语言。每次请求返回的三位数字,包含了请求是否成功、出了什么问题、下一步该怎么做等重要信息。然而很多开发者只认识 200、404、500,遇到其他状态码时一头雾水。本文系统梳理了 HTTP 状态码的分类与常见问题排查方法。
1. 状态码分类总览
HTTP 状态码按第一位数字分为五大类,每一类代表不同的含义:
- 1xx 信息响应:请求已接收,继续处理。属于过渡状态,日常很少见到。
- 2xx 成功响应:请求已成功被接收、理解和接受。
- 3xx 重定向:需要进一步操作才能完成请求。
- 4xx 客户端错误:请求包含语法错误或无法完成。问题出在客户端。
- 5xx 服务端错误:服务器在处理请求时发生了内部错误。问题出在服务端。
2. 2xx 成功:细说常见成功状态
200 OK // 请求成功,最常见的状态码
201 Created // 请求成功且创建了新资源(POST/PUT)
204 No Content // 成功但无返回体(DELETE 常用)
206 Partial Content // 部分内容(断点续传/视频流)
206 Partial Content 的应用
206 是 HTTP 分片传输的核心。客户端通过 Range 请求头指定字节范围,服务端返回 206 状态码和对应范围的数据。这在视频播放、大文件下载、断点续传中非常重要。
# 请求头
Range: bytes=0-1023
# 响应头
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1023/10000
Content-Length: 1024
3. 3xx 重定向:容易混淆的几种跳转
重定向状态码看似相似,实则在语义和行为上有重要区别,特别是对 SEO 有直接影响。
301 Moved Permanently // 永久重定向(SEO 传递权重)
302 Found // 临时重定向(原始,可能改变请求方法)
303 See Other // 临时重定向,强制 GET 方法
304 Not Modified // 资源未修改(协商缓存)
307 Temporary Redirect // 临时重定向,保持请求方法
308 Permanent Redirect // 永久重定向,保持请求方法
301 vs 302:SEO 的关键区别
301 是永久重定向,搜索引擎会把原 URL 的权重转移到新地址;302 是临时重定向,搜索引擎会保留原 URL 的索引。如果 URL 结构永久变更(如网站改版、域名更换),务必使用 301。
304 与缓存机制
304 是浏览器缓存优化的核心。当浏览器请求已缓存的资源时,会带上 If-None-Match 或 If-Modified-Since 请求头。如果服务端判断资源未变化,就返回 304,浏览器直接使用本地缓存,节省了传输时间和带宽。
# 请求头(浏览器)
If-None-Match: "abc123"
If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT
# 响应头(服务器)
HTTP/1.1 304 Not Modified
ETag: "abc123"
4. 4xx 客户端错误:你的请求有问题
4xx 错误表示客户端的请求有问题,服务端无法处理。排查时应先检查请求参数、格式、权限等。
400 Bad Request // 请求参数错误/格式不对
401 Unauthorized // 未认证/未登录
403 Forbidden // 已认证但无权限访问
404 Not Found // 资源不存在
405 Method Not Allowed // 请求方法不允许(如 GET 接口用了 POST)
408 Request Timeout // 请求超时
409 Conflict // 资源冲突(如重复创建)
410 Gone // 资源已永久删除(比404更强)
413 Payload Too Large // 请求体过大
415 Unsupported Media Type // 不支持的媒体类型
422 Unprocessable Entity // 语义错误(参数格式对但内容错)
429 Too Many Requests // 请求过于频繁(限流)
401 vs 403:别再搞混了
401 Unauthorized 的意思其实是"未认证"——你没有登录,或者 token 过期了。403 Forbidden 才是"无权限"——你登录了,但这个资源你不能看。简单记:401 = 你是谁?403 = 我知道你是谁,但你不行。
429 与限流
429 是 API 限流的标准状态码。服务端应同时返回 Retry-After 响应头,告诉客户端多久后可以重试。遇到 429 时,客户端应实现退避重试(exponential backoff),而不是立即疯狂重试。
5. 5xx 服务端错误:服务器出问题了
5xx 错误表示服务端在处理请求时发生了错误。遇到 5xx 时,责任通常在服务端,但也可能是客户端的请求触发了服务端的未处理边界。
500 Internal Server Error // 服务器内部错误(通用)
501 Not Implemented // 服务器不支持该功能
502 Bad Gateway // 网关错误(反向代理收到无效响应)
503 Service Unavailable // 服务不可用(过载/维护)
504 Gateway Timeout // 网关超时(上游服务响应太慢)
507 Insufficient Storage // 存储空间不足
502 vs 504:网关相关的两个常见错误
这两个错误都和反向代理(Nginx、负载均衡器)有关。502 Bad Gateway 表示代理从上游服务器收到了无效响应(比如上游服务挂了、返回了无法解析的内容)。504 Gateway Timeout 表示代理等了太久都没收到上游响应,超时了。简单说:502 = 上游返回了垃圾,504 = 上游响应太慢。
6. 常见问题排查思路
遇到异常状态码时,按以下思路排查可以少走很多弯路:
- 先看网络面板:打开浏览器 DevTools 的 Network 面板,查看完整的请求和响应头
- 确认 URL 和方法:404/405 首先检查 URL 是否正确、HTTP 方法是否匹配
- 检查请求体格式:400/415 通常是 Content-Type 不对或 JSON 格式错误
- 认证信息:401 检查 Authorization 头,403 检查用户角色权限
- 查看服务端日志:500/502 必须查服务端日志才能定位根因
- 用 curl 复现:把请求复制为 curl 命令,排除浏览器缓存和扩展的干扰
推荐两个调试工具:curl 命令在线工具可以快速构造和测试 HTTP 请求;Postman 或 Thunder Client 则适合更复杂的 API 调试场景。
7. 不常见但有用的状态码
除了常见的 200、404、500,还有一些状态码虽然不常用,但在特定场景下非常实用。了解它们可以让你的 API 设计更专业。
100 Continue // 客户端可以继续发送请求体
101 Switching Protocols // 协议切换(如 WebSocket 升级)
202 Accepted // 请求已接受,正在处理(异步任务)
203 Non-Authoritative Information // 代理返回的修改过的响应
300 Multiple Choices // 多个选择,需要用户选择
402 Payment Required // 预留状态码,将来可能用于付费
406 Not Acceptable // 无法生成客户端可接受的内容
407 Proxy Auth Required // 需要代理认证
410 Gone // 资源永久删除(比404语义更强)
416 Range Not Satisfiable // 请求的范围无效
418 I'm a teapot // 愚人节玩笑,部分框架真的实现了
421 Misdirected Request // 请求被发送到了无法产生响应的服务器
425 Too Early // 可能存在重放攻击风险
426 Upgrade Required // 客户端需要升级协议
451 Unavailable For Legal Reasons // 因法律原因不可用
506 Variant Also Negotiates // 内部配置错误
508 Loop Detected // 检测到循环
510 Not Extended // 需要进一步扩展
其中 202 Accepted 特别适合异步任务场景——客户端提交任务后,服务端立即返回 202 和任务 ID,客户端通过轮询或 WebSocket 来获取任务执行结果。451 则是一个很有意思的状态码,专门用于表示因法律原因(如版权、审查)导致内容不可用,命名来源于小说《华氏 451》。
8. API 设计中状态码的选择原则
设计 API 时,正确选择状态码很重要。一个常见的错误是所有错误都返回 200,然后在响应体里放自定义错误码。这种做法虽然"灵活",但违背了 HTTP 语义,会导致缓存、监控、代理等基础设施无法正常工作。
正确的做法是:HTTP 状态码表示协议层面的结果,响应体中的业务错误码表示具体的业务错误。两者配合使用,既符合 HTTP 语义,又能提供足够详细的错误信息。
选择状态码时的判断逻辑:
- 请求成功了吗?→ 2xx
- 需要跳转吗?→ 3xx
- 是客户端的问题吗?(参数错、没登录、没权限、资源不存在)→ 4xx
- 是服务端的问题吗?(代码 bug、服务挂了、超时)→ 5xx
拿不准时,选语义最接近的那个。比如参数格式错误用 400,参数内容不合法用 422,资源不存在用 404,操作冲突用 409。语义准确的状态码,能让前端和运维少走很多弯路。
最后补充一个小知识:状态码的每一位数字都有特定含义。第一位表示类别(成功/重定向/客户端错误/服务端错误),第二位表示更细的分类(如 40x 是语法/认证类错误,41x 是内容协商/长度类错误,42x 是语义/限流类错误)。理解这些规律,遇到不认识的状态码也能猜个八九不离十。