Skip to content
返回博客
教程

HTTP 状态码速查表:每个代码全解析(1xx-5xx)

HTTP 状态码完整速查表:1xx 到 5xx 全分类解析,含 401 与 403 区别、301 vs 302 选择、5xx 排错与 SEO 影响。立即查阅速查表,提升 API 调试效率。

14 分钟

HTTP 状态码速查表:每个代码全解析(1xx-5xx)

打开 DevTools,Network 面板红了一半。同一个接口在生产环境返回 502,本地却是 200,Slack 上同事又问:“这个该是 401 还是 403?” HTTP 状态码三位数字、五个分类,看似简单,选错却会泄漏信息、破坏 SEO,让值班变噩梦。

本文是一份面向一线开发者的完整 HTTP 状态码速查表。一张涵盖生产常见状态码的速查表;针对易混淆组合(301 vs 302401 vs 403404 vs 410502 vs 504)的决策矩阵;一个工具章节,演示如何用 curl、fetch 和 Python requests 检查状态码。下文每个状态码都基于 RFC 9110(当前 HTTP 语义标准)和 IANA HTTP Status Code Registry

速查表:所有 HTTP 状态码一览

下面是生产环境会真正遇到的状态码,按分类整理。容易踩坑的几组,后文会逐一展开。

代码名称何时会遇到
100ContinueExpect: 100-continue 发送大体积 POST
101Switching ProtocolsWebSocket 握手、HTTP/2 升级
103Early Hints服务器在正式响应前先推送 Link
200OKGET、PUT、PATCH 的默认成功
201CreatedPOST 创建了资源(带 Location 返回)
202Accepted异步任务已入队,尚未完成
204No ContentDELETE 成功、PUT 不需要返回响应体
206Partial Content范围请求、视频拖动、断点续传
301Moved Permanently旧 URL 永久退役,搜索引擎转移权重
302Found临时重定向,原 URL 仍是规范地址
303See Other表单 POST 后的 Post/Redirect/Get 模式
304Not Modified条件 GET,ETagIf-Modified-Since 命中
307Temporary Redirect类似 302,但保留方法和请求体
308Permanent Redirect类似 301,但保留方法和请求体
400Bad RequestJSON 格式错误、缺必填字段、Schema 校验失败
401Unauthorized没有凭证或令牌过期
403Forbidden已认证但无权限
404Not Found资源不存在(或被刻意隐藏)
405Method Not Allowed向只支持 GET 的端点发 POST(必须带 Allow
408Request Timeout客户端发送请求耗时过长
409Conflict乐观锁失败、唯一键冲突
410Gone资源已被永久删除,不会再回来
415Unsupported Media TypeContent-Type 错误,比如向 JSON API 发 XML
422Unprocessable Content语法没问题,语义校验失败
425Too EarlyTLS 1.3 早期数据有重放风险
428Precondition Required服务器要求带 If-Match 防止丢失更新
429Too Many Requests触发限流(必须带 Retry-After
451Unavailable for Legal ReasonsDMCA、GDPR 删除、地区屏蔽
500Internal Server Error代码里有未捕获的异常
501Not Implemented不支持该方法或特性(REST 中罕见)
502Bad Gateway上游返回了非法响应
503Service Unavailable维护中或过载
504Gateway Timeout上游没及时返回
507Insufficient StorageWebDAV 磁盘空间不足
508Loop DetectedWebDAV 出现无限重定向或递归
511Network Authentication Required酒店、机场 WiFi 的强制门户

下面按分类展开,配决策矩阵、反模式案例,以及选错状态码带来的 SEO 后果。

HTTP 状态码工作原理(三位数字的解剖)

为什么是三位数字?

HTTP 状态码采用三位十进制数字,源自 HTTP/0.9 的设计需求:信号要定长,便于解析器快速分支判断;又要留足空间容纳新状态码。三位数字给了 900 个可用值(100-999),完全够用,IANA 注册表至今也只用到 60 个左右。

第一位数字代表分类,第二位和第三位则是该分类内的具体编码。如果客户端不认识 418,应当回退按通用 4xx 处理。RFC 9110 §15 对此有明确规定:客户端必须把无法识别的状态码当作所属分类的 x00 处理。

五大分类速览

分类含义是否必须有响应体?默认是否可缓存?
1xx信息性,临时响应,后续还会有内容
2xx成功,请求已被理解和接受通常需要取决于方法
3xx重定向,需要进一步操作可选301308 是;302307
4xx客户端错误,你的问题,改请求是(需说明)通常否
5xx服务端错误,我们的问题,重试可能有效是(需说明)

「默认是否可缓存」这一列要留意。CDN 和浏览器会激进地、永久地缓存 301308,生产环境里选错重定向码很难撤销,因为用户本地已经把重定向缓存死了。SEO 章节会再次提到这一点。

想深入理解 URL 结构(重定向码就是围绕 URL 工作的),URL 编码与解码:百分号编码开发实战指南会从百分号编码、查询字符串讲到字节级处理流水线,逐层讲清是什么决定了一个 URL 是否合法。

1xx——信息性响应(你究竟何时会遇到)

大多数开发者好几年都未必直接见到 1xx。它们是临时响应,服务器在告诉客户端”我还在,继续”。浏览器 DevTools 通常会隐藏,多数 HTTP 库会把它们折叠进最终响应里。

下面每个状态码,MDN 的 HTTP 响应状态参考都是友好的二次校验来源,定义存疑时不妨对照查阅。

100 Continue

客户端在请求头中发送 Expect: 100-continue,先停下来再发送大体积请求体。服务器若愿意接收,回 100 Continue;若打算拒绝,则回 4xx。这能省下大块上传带宽:服务器要因为缺一个头部就拒绝请求时,没必要先把 200 MB 数据传过去。

curl -v -H "Expect: 100-continue" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @big-file.bin \
  https://api.example.com/upload

如果你在详细输出里没看到 < HTTP/1.1 100 Continue,多半是客户端把这个头部剥掉了,或服务器不支持。

101 Switching Protocols

把 HTTP 连接升级为 WebSocket 或 HTTP/2 连接的握手过程。客户端发送 Upgrade: websocket,服务器回 101 Switching Protocols,从那一刻起这条连接走的就是另一种协议。在任何聊天应用、实时面板或协作工具的 Network 面板里都能看到。

103 Early Hints

一个相对较新的状态码(RFC 8297,2017 年),允许服务器在主响应就绪之前先发送 Link 头作为预加载提示。浏览器在服务器还在渲染时就开始拉取 CSS 和 JS。截至 2026 年,Cloudflare、Fastly、Vercel 都已在生产环境支持 103,它是 HTTP/2 服务器推送(已在 Chrome 中废弃)的现代替代方案。

HTTP/1.1 103 Early Hints
Link: </styles.css>; rel=preload; as=style
Link: </app.js>; rel=preload; as=script

HTTP/1.1 200 OK
Content-Type: text/html
...

反模式排查:预期能看到 1xx 但客户端始终收不到,问题通常出在反向代理上。较旧版本的 nginx 会把 Expect: 100-continue103 Early Hints 直接剥掉。怀疑服务端坏掉之前先检查代理配置。

2xx——成功(远不只 200)

凡事都返回 200 OK 是 REST API 里最常见的代码味道。2xx 家族携带的语义信息能让客户端更聪明、缓存更高效。

200 OK

默认值。GET 返回资源,PUT 返回更新后的资源(或 204),PATCH 返回打了补丁的资源。没有理由用更具体的状态码时,就用 200

201 Created

创建新资源的 POST 应当返回 201,并附带指向新资源的 Location 头。RESTful 客户端正是通过这个头部来发现刚刚创建的资源的规范 URL。

HTTP/1.1 201 Created
Location: /api/users/42
Content-Type: application/json

{"id": 42, "name": "Ada Lovelace"}

202 Accepted

服务器收下了请求,但还没处理完。适用于异步任务,客户端应当轮询、订阅 webhook 或访问状态接口。响应体里通常带一个 job ID。

204 No Content

成功,但没有响应体。常见于 DELETE(资源都没了,还能返回什么)和那些客户端已知新状态的 PUT。表单提交返回 204,浏览器不会切换当前页面,单页应用中那种「发完就不管」的操作很有用。

206 Partial Content

范围请求的响应:客户端用 Range: bytes=1000-2000 请求第 1000 到 2000 字节,服务器只返回这一段。视频流、断点续传、基于 HTTP 的文件同步都依赖 206

决策:POST 该用 200、201 还是 204

场景状态码响应体
POST 创建了新资源201 Created新资源(或仅 ID)+ Location
POST 触发了异步任务,结果未就绪202 AcceptedJob ID、轮询 URL
POST 是动作而非资源操作(如 /login200 OK动作结果(令牌、状态)
POST 成功但响应体为空204 No Content(无)

200201 之间犹豫时,问自己:“服务器是不是创建了一个有自己 URL 的资源?“是,用 201;否则 200

3xx——重定向(301 vs 302 vs 307 vs 308)

重定向是被误用最多的分类。301302307308 之间的差异,可以归结为三个相互独立的问题:迁移是否永久?方法是否保留?响应是否可缓存?

301 Moved Permanently

资源已经搬走,再也不会回来。搜索引擎会把链接权重转移到新 URL。浏览器和 CDN 会无限期缓存 301:用 301/old 重定向到 /new,事后想反悔,已经缓存重定向的用户就会一直被送到 /new(直到他们清缓存为止)。

历史上,浏览器在收到 301 时可能会改写请求方法(POST → GET),HTTP/1.1 引入 308 就是为了解决这个问题。

302 Found

临时重定向。原 URL 仍是规范地址,搜索引擎应继续索引原地址。适用于 A/B 测试路由、维护页、「请先登录」流程。

301 一样,浏览器历史上也会在 302 上把 POST 改写成 GET。如果你需要重定向 POST 并保持 POST,请改用 307

303 See Other

总会把方法改写为 GET。Post/Redirect/Get 模式:表单 POST 到 /submit,服务器返回 303Location: /thank-you,浏览器执行 GET /thank-you。刷新感谢页不会再次提交表单。303 就是为这个场景设计的。

304 Not Modified

条件响应。客户端发送 If-None-Match: "abc123"(或 If-Modified-Since),服务器检查资源是否变化,没变就返回 304,不带响应体。浏览器使用本地缓存副本。每一层 CDN 和缓存正是靠这个机制把网站维持得飞快。

307 Temporary Redirect

类似 302,但方法不能改。POST 仍是 POST,请求体保留。需要在非 GET 请求上做临时重定向时用它。

308 Permanent Redirect

类似 301,但方法不能改。对接受 POST/PUT 的 API 来说,是更现代、更安全的永久重定向方案。

决策矩阵:该用哪个重定向码?

永久(永久缓存)临时(不缓存)
方法可以改成 GET301 Moved Permanently302 Found
方法必须保持不变308 Permanent Redirect307 Temporary Redirect

特例:如果就是要把 POST 改成 GET(Post/Redirect/Get 模式),用 303 See Other

带浏览器导航的 HTML 页面用 301302 一般没问题,因为本来就是 GET。但 API 和表单更建议用 308307,避免方法被悄悄改写。

4xx——客户端错误(如何选对)

4xx 表示客户端做错了事。4xx 的词汇越丰富,API 用起来越顺手:客户端可以基于状态码分支判断,而不必去解析错误字符串。

400 Bad Request

通用语法错误。JSON 格式错误、结构层面缺必填字段、服务器根本无法解析的请求。如果请求能解析但业务校验失败,更适合用 422

401 Unauthorized 与 403 Forbidden

HTTP 中最容易混淆的一对。看清差异后并不难:

  • 401 Unauthorized:请求缺少有效身份凭证。服务器不知道你是谁。再次发送凭证(或刷新令牌)也许能解决。响应必须按 RFC 9110 §15.5.2 包含 WWW-Authenticate 头。
  • 403 Forbidden:服务器知道你是谁,仍然拒绝。再发一次也没用。需要换一组凭证或获取额外权限。
你看到真实情况
401WWW-Authenticate: Bearer没有令牌、令牌过期或令牌无效
登录成功后出现 403已登录,但当前用户无权访问该资源
登录成功后出现 401Bug,你大概率想要的是 403

反模式:用 403 替代 404。一些站点对未登录用户访问 /admin/dashboard 返回 403,这等于泄漏了 /admin/dashboard 的存在。GitHub 的做法是:你不是成员的私有仓库一律返回 404,从你的视角看资源「不存在」。这是有意识的信息隐藏策略,不是 bug。

404 Not Found 与 410 Gone

两者都在说”这里没这个资源”,区别在于永久性和 SEO 影响。

  • 404 Not Found:可能存在,可能不存在,可能还会回来。搜索引擎会持续来探。
  • 410 Gone:曾经存在,被刻意删除,不会再回来。搜索引擎会更快从索引中剔除。

想让被删的商品页立刻从 Google 索引里消失,就用 410。只是 URL 临时坏了,404 就够。

405 Method Not Allowed

URL 存在,但不接受当前方法。响应必须包含列出受支持方法的 Allow 头。

HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS
Content-Type: application/json

{"error": "POST is not allowed on this endpoint"}

漏写 Allow 头是手写 REST API 里第一名的契约违规。

408 Request Timeout

客户端开始发送请求后突然没声音了,服务器等不下去就放弃。和 504 Gateway Timeout 不同:504 是上游慢,408 是客户端自己太慢。

409 Conflict

请求与当前状态冲突。最常见用法是乐观锁:客户端发送 If-Match: "etag-v3",但服务端当前 ETag 是 "etag-v4",更新被驳回,返回 409

410 Gone

见上文,永久删除。适合从搜索索引中移除已软删除的记录。

415 Unsupported Media Type

客户端发了服务器不认识的请求体。向只接受 JSON 的 API 发送 XML,就会拿到 415。响应应当提示可接受的类型。

422 Unprocessable Content

请求能正常解析,但语义校验不过。RFC 9110 在 2022 年终于把它从 WebDAV 升级进核心规范。校验错误就用 422

{
  "error": "validation_failed",
  "details": [
    {"field": "email", "message": "must be a valid email"},
    {"field": "age", "message": "must be at least 13"}
  ]
}

API 在 400422 之间难以抉择时,规则是:解析不了用 400,解析得了但语义不通用 422

425 Too Early

服务器不愿冒险处理可能是 TLS 1.3 早期数据重放的请求。主要影响 CDN 和反向代理。

428 Precondition Required

服务器坚持要求客户端发送 If-MatchIf-Unmodified-Since,以避免丢失更新问题。常用于协同编辑类 API。

429 Too Many Requests

触发限流。响应必须带 Retry-After(秒数或 HTTP 日期),让规范的客户端知道该退避多久。

HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json

{"error": "rate_limited", "limit": 100, "window": "1m"}

数字「451」致敬布拉德伯里的《华氏 451》。但用例并非虚构:DMCA 删除、GDPR 被遗忘权请求、国家级地理封锁,都适用 451。响应应按 RFC 7725 包含 Link 头,指向要求屏蔽的法律主体。

418 I’m a Teapot(彩蛋)

这状态码是真的。RFC 2324 是 1998 年愚人节玩笑,但因为太多产品认真实现了它,IETF 索性把它留在了规范里。别真的把 418 用到生产 API 上,大多数反向代理和负载均衡处理不好它。

决策矩阵:该用哪个 4xx?

场景状态码
请求体格式错误或无法解析400
没有身份认证 / 令牌过期401
已认证但无权限403
URL 不存在(或被刻意隐藏)404
URL 曾经存在,被刻意删除410
错误的 HTTP 方法405(带 Allow
错误的 Content-Type415
乐观锁冲突409
校验错误(解析得了但通不过校验)422
限流429(带 Retry-After
因法律原因屏蔽451

5xx——服务端错误(究竟哪里坏了)

5xx 是「我们的锅」。值班工程师最关心是哪个 5xx 把自己凌晨三点叫醒,因为状态码会告诉你先去查哪一层。

500 Internal Server Error

万能兜底。几乎一定是未捕获的异常冒泡到框架的默认处理器。它对原因毫无暗示,所以结构化日志比状态码本身更重要。

501 Not Implemented

服务器根本不支持该方法。和 405 不同:405 是「这个 URL 不允许此方法」,501 在说”本服务器压根不知道 PROPFIND 是什么”。在 REST API 中很少见。

502 Bad Gateway

反向代理或负载均衡从上游收到了非法响应。上游确实回复了,但内容是垃圾:协议错误、响应头格式错乱、响应中途断连。从 CDN 看到 502,源站很可能在崩溃或返回截断的响应体。

503 Service Unavailable

服务器有意暂时不接收请求。适用于维护窗口或优雅过载响应,应当带 Retry-After

504 Gateway Timeout

反向代理等上游响应一直没等到。上游变慢或卡住,和 502 不同:502 是上游回了垃圾。

502 vs 504:值班诊断

你看到第一步检查
502 Bad Gateway上游返回了非法数据,查源站日志,看是否崩溃、响应残缺、协议不匹配
504 Gateway Timeout上游卡死,查源站 CPU、数据库查询、下游 API 调用,以及代理的 proxy_read_timeout

常见的混淆:一条耗时 60 秒的数据库查询,代理 30 秒超时就显示 504;应用服务器 90 秒超时抛异常就显示 500。同一个根因,不同的状态码、不同的日志行,监控面板要把两者都拎出来。

507 Insufficient Storage

WebDAV 专用。服务器磁盘已满。若非 WebDAV API 也返回这个,那是有人在硬塞含义。

508 Loop Detected

WebDAV PROPFIND 操作中出现无限递归。极其罕见。

511 Network Authentication Required

强制门户专用:酒店或机场的 WiFi 用 511 告诉你浏览器「先登录门户页面」。响应里会带一个指向门户页的 Location

排错矩阵:先排查哪一层

状态码应用代理数据库网络
500可能(未捕获的数据库错误)
502是(上游响应畸形)可能(TCP 重置)
503是(维护开关)是(限流拒绝)
504是(处理慢)是(超时配置)是(慢查询)是(DNS、丢包)

HTTP 状态码常见反模式

下面这五个错误,几乎包揽了我代码评审里看到的大部分糟糕实现。

1. 把错误包在 200 OK 里返回

HTTP/1.1 200 OK
{"success": false, "error": "user_not_found"}

每一个监控工具、CDN、缓存层从此都以为请求成功了。重试逻辑失灵,懂状态码的负载均衡会把坏流量转给「健康」后端。这种模式起源于 JSON-RPC,被 GraphQL 沿用,GraphQL 这么做是因为部分成功需要逐字段错误报告,情有可原。REST 没有借口:客户端错误用 4xx、服务端错误用 5xx,结构化细节放到响应体里。

2. 401 和 403 混用

401403 用得不一致,攻击者就能通过探测 API 推断哪些资源存在。定一个策略:要么对「你看不到这个」一律返回 404(GitHub 私有仓库的做法),要么始终返回 403。不一致本身就是信息泄漏。

3. 用 404 掩盖 403

有时正确,常常是 bug。GitHub 对私有仓库返回 404 是有意为之,仓库的存在本身就是敏感信息。但如果你的 API 对「该账号已被封禁」也返回 404,正常用户就分不清自己是输错了用户名还是被封了。把策略写明白,并贯彻一致。

4. 把 500 当默认兜底

各种框架都让这件事很容易,问题正在于此。每一个未捕获的异常都变成 500,告警系统就分不清是「数据库挂了」还是「用户传了个格式错乱的 UUID」。校验错误要捕获并抛 400422;ORM 抛的 NotFound 要捕获并抛 404500 留给真正出乎意料的故障,抛 500 时还要带请求 ID,方便日后关联排查。

5. 重定向链过长

每一跳都要一次往返。/old/intermediate/canonical,最坏情况要多两次 DNS 查询和两次 TCP 握手。Google 会专门下调超过 3 跳重定向链的爬取优先级;浏览器一般在约 20 跳后切断重定向链以防死循环。要在源头收拢,CDN 配置里改,或者在应用的重定向映射里改。

HTTP 状态码与 SEO

搜索引擎把状态码当作权威信号,决定一个 URL 是保留、丢弃还是迁移。选错了,排名就跟着动。

301 vs 302(链接权重)

301 Moved Permanently 会传递 PageRank:Google 会把所有指向旧 URL 的信号都视为新 URL 的,把新 URL 当作规范地址。302 Found 不传递链接权重(或根据 Google 启发式判断缓慢传递)。某个 URL 是永久改名了,用 301;把游客重定向到 /login,用 302

404 vs 410 vs 软 404

Google 区分三种「不存在」的状态:

  • 404 Not Found:Google 会定期回访,URL 会在索引中保留一段时间。
  • 410 Gone:Google 剔除 URL 更快,往往一个抓取周期内就处理完。
  • 软 404:Google 用来形容那些返回 200 OK 但内容显示「未找到」的页面。Google 会基于内容模式自动检测,并照样按 404 处理;但你已经浪费了一次抓取配额,还可能稀释真实内容。

清理过期索引时,对真正永久删除的 URL 一定要返回真正的 410

5xx 与抓取预算

当一个站点持续返回 5xx,Google 爬虫会主动降低抓取频率。Search Console 的「Crawl Stats」报告里能看到这一点:5xx 错误持续飙升,可能让抓取预算掉好几天,新页面的入索引时间也会跟着拖长。把 5xx 比例既当可靠性指标,也当 SEO 指标。

实际坏掉但写着 200 OK

返回 200 OK 配错误页面(即软 404 反模式)是 SEO 最糟的情况。Google 会去索引那条错误信息,给它一个根本排不上的关键词,然后慢悠悠地才意识到这页坏了。哪怕你的单页应用要渲染一个友好的错误界面,服务器也必须返回正确的状态码。

如何检查 HTTP 状态码(工具篇)

看不见就修不了。下面三种工具,每位活跃的开发者至少要熟练掌握一种。

浏览器 DevTools 的 Network 面板

Chrome、Firefox、Safari 都会在 Network 标签页显示 Status 列。看不到 Status Text,右键列头加上即可。几个实用技巧:

  • Preserve log:跨页面导航保留记录,便于完整观察重定向链。
  • 按状态码过滤:Chrome 中输入 status-code:5xx 就能只看服务端错误。
  • Replay XHR:任意请求右键 → Replay XHR,无需刷新页面即可重发。

对于重定向,展开请求即可看到每一跳和对应的状态码。

curl(万能解法)

curl 什么都能看到。下面这几种模式能解决 90% 的调试问题:

# 仅查看状态码
curl -o /dev/null -s -w "%{http_code}\n" https://api.example.com/users/1

# 仅查看响应头(HEAD 请求,跟随重定向)
curl -I -L https://example.com

# 完整 verbose 输出,含请求和响应头
curl -v https://api.example.com/users/1

构造测试 URL、查询字符串里有特殊字符时,用 --data-urlencode 让 curl 自动处理编码,或者把 URL 粘贴到URL 编码解码工具里,确认实际发到线上的字节是什么。

# curl 会自动对查询值进行编码
curl -G "https://api.example.com/search" \
  --data-urlencode "q=hello world & friends"

# 实际发送:GET /search?q=hello%20world%20%26%20friends

JavaScript fetch

Response.status 属性是状态码整数;Response.ok 在任何 2xx 时为 true

const res = await fetch('https://api.example.com/users/1');

console.log(res.status);      // 200
console.log(res.statusText);  // "OK"
console.log(res.ok);          // true

if (!res.ok) {
  if (res.status === 401) {
    // 刷新令牌后重试
  } else if (res.status === 429) {
    const retryAfter = Number(res.headers.get('Retry-After')) || 1;
    await new Promise(r => setTimeout(r, retryAfter * 1000));
  } else if (res.status >= 500) {
    throw new Error(`Server error: ${res.status}`);
  }
}

axios 中同样的逻辑放在拦截器里:

import axios from 'axios';

axios.interceptors.response.use(
  response => response,
  error => {
    const status = error.response?.status;
    if (status === 401) {
      // 跳转到登录页
    }
    return Promise.reject(error);
  }
);

Python requests

import requests

r = requests.get('https://api.example.com/users/1')

print(r.status_code)  # 200
print(r.reason)       # 'OK'

# 4xx/5xx 时抛 requests.exceptions.HTTPError
r.raise_for_status()

# 手动处理
if r.status_code == 429:
    retry_after = int(r.headers.get('Retry-After', '1'))
    time.sleep(retry_after)
elif 500 <= r.status_code < 600:
    raise RuntimeError(f'Server error: {r.status_code}')

raise_for_status() 是 Python 处理「4xx/5xx 直接抛错」的惯用法。脚本里希望出错就抛异常、不想手动分支判断 status_code 时,就用它。

Postman 与 Bruno

两者都允许在测试脚本里对状态码做断言:

// Postman/Bruno test script
pm.test("Status is 201", () => {
  pm.response.to.have.status(201);
});

pm.test("Has Location header", () => {
  pm.expect(pm.response.headers.get('Location')).to.match(/^\/users\/\d+$/);
});

把这些断言放进 CI,拿预发环境跑,上生产前就能发现契约违规。

FAQ

401 和 403 有什么区别?

401 Unauthorized 表示服务器不知道你是谁,凭证缺失、过期或无效。403 Forbidden 表示服务器知道你是谁,但仍然拒绝。换一组凭证可能解决问题,用 401;换了也没用,用 403

什么时候该用 301,什么时候该用 302?

迁移是永久性的(旧 URL 永远不回来,希望搜索引擎把链接权重转移到新 URL)用 301。临时重定向(登录流程、A/B 测试、维护页等)原 URL 仍是规范地址时,用 302。API 更建议用 308307,因为它们会保留请求方法。

502 Bad Gateway 错误是什么意思?

502 表示反向代理或负载均衡从上游服务器收到了非法响应。上游确实回了,但内容是垃圾:协议错乱、响应头畸形或响应中途断连。它和 504 Gateway Timeout 不同,后者是上游根本没回。第一时间查源站日志,看是否崩溃或响应被截断。

什么是「软 404」?

「软 404」是指页面返回 200 OK,但内容上是「未找到」。Google 会启发式地识别并照 404 处理。它会浪费抓取预算,还可能稀释真实内容。即便单页应用要渲染一个友好的错误界面,服务器也必须返回真正的 404410

什么时候用 422 而不是 400?

服务器根本无法解析请求时(JSON 格式错误、缺结构性字段、语法错误)用 400 Bad Request。请求能正常解析但业务校验不过(邮箱格式不对、值越界、字段语义自相矛盾)用 422 Unprocessable Content。一句话总结:400 管语法,422 管语义。

收到 429 Too Many Requests 该如何应对?

读取 Retry-After 头(秒数或 HTTP 日期),至少退避这么久再重试。没有 Retry-After 时,从 1 秒起做带抖动的指数退避。绝不要立刻重试,那是封号的最快方式。

2026 年了,1xx 信息性状态码还在用吗?

是的,但绝大多数对应用代码不可见。100 Continue101 Switching Protocols 是 HTTP/1.1 的基础特性。103 Early Hints 越来越多被 Cloudflare、Fastly、Vercel 用于在主响应前推送预加载提示,能明显改善 Largest Contentful Paint 指标。多数 HTTP 库会把 1xx 折叠进最终响应,因此通常只在 DevTools 或 curl -v 里能看到。

418 「I’m a teapot」是真的状态码吗?

意外地,是。RFC 2324 是 1998 年的愚人节玩笑,但因为足够多的产品真把它实现了,IETF 在 RFC 7168 里把它保留下来。生产环境别用 418:很多反向代理和负载均衡处理不好它,而且它在玩笑之外没有任何实际用途。