REST API 状态码最佳实践:2xx/4xx/5xx 怎么用才对

4437 字
22 分钟
REST API 状态码最佳实践:2xx/4xx/5xx 怎么用才对

状态码用错,联调就变成了猜谜#

接口设计里最被低估的一环,就是状态码。很多后端开发者把精力花在业务逻辑上,状态码却随手一写——成功就 200,失败就 500,参数不对也 200(把错误塞进响应体里)。结果前端拿到响应,得先扒开 body 猜”这到底是成了还是败了”。

状态码是 HTTP 协议给接口的第一层语义,用对了,前端不用猜、监控告警有据可依、排查方向一眼能定。这篇讲清楚 REST API 里 2xx / 3xx / 4xx / 5xx 的正确用法、常见误用与排查思路,并给一张状态码选用对照表。

查任何状态码的标准短语、含义与排查建议,可以用星点 HTTP 状态码查询,输入数字即查。


先立好框架:首位数字定责任#

首位分类谁的问题接口设计该怎么做
2xx成功无正常返回数据
3xx重定向客户端配合慎用,明确语义
4xx客户端错误请求方给出可操作的错误信息
5xx服务器错误服务方记录日志、告警

设计接口时心里要有这张表:4xx 是”你发错了”,5xx 是”我挂了”。很多接口的混乱,根源就是没守住这条边界。


2xx:成功状态码的正确用法#

2xx 不是只有 200 一个选择。用对细分状态码,前端能少很多 if-else。

状态码短语什么时候用典型场景
200OK通用成功,返回资源或结果查询、更新成功
201Created创建了新资源POST 创建成功,最好带 Location 头指向新资源
202Accepted已接受,异步处理中任务排队、异步作业
204No Content成功但无返回体删除成功、无内容可回

200 vs 201:创建该返回哪个#

一个常见的”半对半错”:创建资源一律返回 200。语义上,创建成功用 201 更准确,并配合 Location 头让客户端知道新资源在哪。虽然很多团队图省事全用 200 也能跑通,但状态码越准确,前后端契约越清晰——前端看到 201 + Location,就能直接跳转到新资源,不用再从 body 里猜 ID。

200 vs 204:删除该返回哪个#

删除成功,返回 200 + 一个空 body,还是返回 204?规范上 204 No Content 更准确——它明确告诉客户端”成功了,但没有任何内容可返回”。前端看到 204 就知道不用解析 body。当然,如果删除成功后还想返回一些元信息(比如删除时间),那用 200 带 body 也没问题。关键是别 204 却还带了个 body,自相矛盾。

202:异步任务的正确姿势#

如果接口是异步的——请求提交后,任务要排队慢慢执行——返回 202 Accepted 是最诚实的做法。它告诉客户端”我收下了,但还没做完”。配合后续的轮询或回调机制,客户端就知道该去查任务状态,而不是傻等。

200 不代表业务成功#

另一个关键提醒:200 不代表业务成功。很多接口业务失败也返回 200,只在 body 里放 {"code": 500, "msg": "..."}。这种做法让 HTTP 层的监控、缓存、重试机制全部失效。如果一定要用”业务码”体系,也应当让 HTTP 状态码与业务结果保持一致——业务失败就返回对应的 4xx/5xx,把业务码放进 body 作为补充。


3xx:重定向,REST 里要慎用#

3xx 在 REST API 里用得少,但一旦用错也麻烦。关键区分:

状态码短语语义是否改变方法
301Moved Permanently永久重定向可能把 POST 变 GET
302Found临时重定向可能把 POST 变 GET
303See Other用 GET 查看另一个资源明确改为 GET
307Temporary Redirect临时重定向,保持方法不改变
308Permanent Redirect永久重定向,保持方法不改变

REST API 里最该记住的一点:301/302 可能被客户端把 POST 改成 GET,导致请求体和语义丢失。 如果重定向后必须保持原方法(比如一个 POST 被重定向到另一个 URL 继续处理),用 307/308。如果只是”创建成功,去用 GET 看结果”,用 303 更规范。

SEO 场景里 301 常用来做域名跳转、HTTP 转 HTTPS、旧 URL 迁移,这个在 HTTP 状态码查询 里也有联动说明(301/302/307/308 互相关联跳转)。


4xx:客户端错误,最容易用错的一类#

4xx 表示”请求本身有问题”。它细分很多,用错了会让前端误导排查方向。

状态码短语正确用法常见误用
400Bad Request请求格式错误、JSON 解析失败什么都往 400 里塞
401Unauthorized未认证:凭证缺失或无效误当成”无权限”
403Forbidden已认证但无权限误当成”未登录”
404Not Found资源不存在用 404 隐藏”无权限”
405Method Not Allowed方法不被允许用 404 或 500 代替
409Conflict资源冲突(如重复创建)用 400 代替
422Unprocessable Entity参数校验失败用 400 代替
429Too Many Requests触发限流用 500 代替

401 vs 403:最经典的一对混淆#

  • 401 Unauthorized:字面意思是”未授权”,但标准语义其实是**“未认证”**——你是谁都不知道(没带凭证、凭证无效或过期)。客户端看到 401,应该引导用户重新登录。
  • 403 Forbidden:“已认证但无权限”——知道你是谁,但你不允许做这件事。客户端看到 403,重新登录也没用,是权限配置问题。

一句话:401 是”请先证明你是谁”,403 是”证明了你也不行”。 很多系统把”登录过期”和”权限不足”都写成 401 或都写成 403,导致前端无法区分该跳登录还是提示无权限。

400 vs 422:参数问题到底用哪个#

  • 400 Bad Request:偏”请求本身格式不对”——JSON 解析失败、协议层错误。
  • 422 Unprocessable Entity:偏”格式对但业务校验不过”——字段格式合法,但值不满足业务规则(如年龄为负)。

现代 API 框架(尤其 Rails 及受其影响的生态)倾向于用 422 表示参数校验失败。二者没有绝对的谁对谁错,但团队内部要统一:要么都用 400,要么都用 422,别一半一半。

404 的一个反模式#

有些后端故意用 404 隐藏资源的存在性(比如无权限访问别人的资源时也返回 404,避免暴露”这资源存在”)。这在隐私敏感场景有合理性,但会让前端误以为资源真的不存在。更规范的做法是:公开资源用 403 明确”无权限”,只有确实需要隐藏存在性时才用 404。


5xx:服务器错误,别把客户端错误往这里塞#

5xx 表示”服务器处理出错”,责任在服务方。设计上它应该少而准。

状态码短语正确用法常见误用
500Internal Server Error未捕获异常、无法分类的错误把参数错误、限流也当 500
501Not Implemented服务器不支持该功能极少用到,常被误用
502Bad Gateway网关从上游收到无效响应与 504 混淆
503Service Unavailable服务不可用(过载/维护/降级)用 500 代替
504Gateway Timeout网关等待上游超时与 502 混淆

几个设计要点:

  1. 参数错误、权限问题绝不该是 5xx。客户端发了个坏请求,你返回 500,等于把锅甩给自己,还污染了服务器错误率的告警。
  2. 503 用于主动降级和限流兜底。服务过载时主动返回 503(可带 Retry-After 头),比把请求压到超时强得多。
  3. 网关场景分清 502 和 504:502 是”上游回了句听不懂的话”(无效响应),504 是”上游一直没吭声”(超时)。

错误响应体:状态码之外的第二层语义#

状态码说清了”是哪类错”,body 还要说清”具体错在哪、怎么改”。好的错误响应体有这几个要素:

字段作用举例
错误码/类型程序可识别的错误类型VALIDATION_ERROR、RATE_LIMITED
消息给人看的错误描述”email 字段不能为空”
字段级错误具体哪个字段错了{"email": "格式不正确"}
请求 ID便于查日志定位req_abc123

设计原则:状态码负责”大类”,body 负责”细节”,两者别打架。 状态码是 422,body 就别写”服务器内部错误”。一个请求 ID 尤其重要——生产环境排查时,用户报一个错,有请求 ID 就能在日志里秒定位。


幂等性与状态码的关系#

状态码设计还和”幂等性”有关——同一个请求重复发,结果是否一致:

方法幂等吗相关状态码
GET是200
PUT是200 / 204
DELETE是204 / 404
POST否(重复会创建多个)201 / 409

POST 不幂等,所以重复提交容易产生重复资源。这正好解释了 409 Conflict 的价值:如果客户端带了唯一标识(如幂等键)重复创建,服务端可以返回 409 而不是又创建一个。理解幂等性,能帮你决定”什么时候该返回 409”。


状态码选用对照表:把操作映射到状态码#

这是可以直接抄进团队规范的一张表:

操作成功失败场景与对应状态码
查询资源200不存在 → 404
创建资源201参数校验不过 → 422/400;重复 → 409
更新资源200不存在 → 404;无权限 → 403;参数错误 → 422/400
删除资源204不存在 → 404;无权限 → 403
未认证—凭证缺失/无效 → 401
无权限—已认证但无权限 → 403
方法不支持—405(配合 Allow 头)
限流—429(配合 Retry-After 头)
服务器内部错误—500
上游异常(网关)—502 / 504

把这张表贴进接口文档,前后端的沟通成本会大幅下降。


常见误用案例复盘:看看这些问题你是不是也踩过#

把真实项目里高频出现的状态码错误摆出来复盘,比抽象讲规则更有用:

误用做法为什么错应该怎么做
登录过期返回 403前端无法区分”要重新登录”还是”没权限”未认证用 401,无权限才用 403
参数校验失败返回 500客户端错误被算成服务器错误,污染告警用 400 或 422
资源不存在返回 200 + {code:404}HTTP 层监控、缓存全部失效直接用 404
创建成功返回 200丢掉了 201 和 Location 的语义用 201 + Location 头
限流返回 500客户端被误判为服务器故障用 429 + Retry-After
删除成功返回 200 + 空 body语义模糊,前端不知要不要解析 body用 204 No Content
方法不支持返回 404让客户端误以为资源不存在用 405 + Allow 头

这些错误有个共同根因:把”业务结果”和”HTTP 语义”混在一起,或者干脆图省事全用一个码。 状态码用对了,前端不用猜、告警有据可依、排查方向一眼能定,这笔投入是值得的。


状态码与 RESTful 资源设计的配合#

状态码不是孤立的,它和 RESTful 的资源设计配合使用才完整:

  • 资源路径对应 404 的边界:/users/123 里的 123 不存在时返回 404,是 REST 的经典语义。如果 404 被滥用去表达”权限不足”,资源的语义就被污染了。
  • 幂等操作对应 2xx 的细分:PUT(幂等更新)返回 200 或 204,DELETE(幂等删除)返回 204,POST(非幂等创建)返回 201。状态码在这里承载了”这个方法是否幂等”的信息。
  • 子资源与 404:/users/123/orders/456 中,用户存在但订单不存在,返回 404 比返回 400 更准确——它指的是”这个子资源”找不到,而不是请求格式错。

一句话:状态码是资源语义的一部分,不是随手填的数字。 设计 REST 接口时,把”每个资源在每种操作下成功/失败返回什么码”当成接口契约的一部分来设计,而不是写完逻辑再补。


排查思路:拿到状态码后怎么走#

查状态码时,按这个顺序走,定位会快很多:

  1. 看首位:4xx 先怀疑自己发的请求(URL、参数、凭证、权限),5xx 先怀疑服务端。
  2. 看具体码:401 检查 Token 是否缺失/过期;403 检查权限配置;404 检查 URL 与路由;422 检查参数校验规则。
  3. 动手复现:用 HTTP 请求测试器 原样重发,排除前端拼接问题,并抓取完整响应头。
  4. 看响应体与响应头:错误信息、Retry-After、Location 等头往往藏着关键线索。

星点 HTTP 状态码查询 内置了每个状态码的含义、常见原因与排查建议,未收录的状态码按首位归类给通用说明,输入即查,配合上面这套思路可以快速下结论。


常见问题(FAQ)#

401 和 403 有什么区别? 401 是"未认证"(你是谁都不知道,凭证缺失或无效);403 是"已认证但无权限"(知道你是谁,但不允许你做这件事)。
400 和 422 该怎么选? 400 偏"请求格式不对"(JSON 解析失败等);422 偏"格式对但业务校验不过"(字段值不合法)。团队内部统一用一个即可,别混用。
业务失败可以都返回 200 吗? 技术上能跑通,但不推荐。200 包业务错误会让 HTTP 层的监控、缓存、重试全部失效。建议让 HTTP 状态码与业务结果一致,业务码作为 body 补充。
404 和 403 有什么区别? 404 表示服务器找不到资源(URL 错误、资源不存在);403 表示服务器理解请求但拒绝执行(权限不足)。
502 和 504 的区别? 502 Bad Gateway 表示网关从上游收到无效响应;504 Gateway Timeout 表示网关等待上游响应超时。
429 和 503 在限流场景怎么选? 429 表示"你请求太频繁"(客户端被限流),503 表示"我暂时扛不住"(服务端主动降级/过载)。都建议带 Retry-After 头告诉客户端何时重试。
301 和 308 有什么区别? 301 是永久重定向但可能把 POST 改成 GET;308 也是永久重定向但严格保持方法不变。REST API 里要保持方法就用 308。
错误响应体应该包含什么? 建议包含程序可识别的错误码、给人看的消息、字段级错误(校验场景)和请求 ID,便于定位与排查。
未收录的状态码能查吗? 能。工具按状态码首位分类给出通用说明,例如 499 归为 4xx 客户端错误。
499、599 这些非标准码是什么? 这些是部分服务器(如 Nginx)自定的非标准码:499 常见于 Nginx,表示"客户端在服务器响应前主动断开连接"。工具按首位归类为 4xx 并给出通用说明。
状态码和 REST 资源路径怎么配合? 路径里的资源标识不存在时用 404,子资源不存在也用 404;权限不足用 403;请求格式/校验问题用 400/422。状态码是资源语义的一部分,应随资源设计一起定。
405 应该返回什么信息? 405 Method Not Allowed 应配合 Allow 响应头,告诉客户端哪些方法被允许(如 Allow: GET, POST),而不是只返回一个冷冰冰的数字。
状态码是越多越细越好吗? 不是。关键是"准"而不是"多":常用几十个码已经够覆盖绝大多数场景。过度细分(自造一堆非标准码)反而增加前后端的认知成本。
联调时状态码对不上怎么办? 用 HTTP 请求测试器原样重发,确认是前端拼装问题还是后端返回问题;再用状态码查询工具对照每个码的标准语义,判断后端用法是否规范。

一分钟速查清单#

设计接口返回状态码时,按这个清单自查:

  1. 成功细分了吗(查询 200、创建 201、删除 204、异步 202);
  2. 未认证用 401、无权限用 403,别混;
  3. 参数校验用 400 或 422,团队内统一;
  4. 客户端错误没被塞进 5xx;
  5. 错误响应体里有错误码、消息、请求 ID;
  6. 限流用 429 + Retry-After,降级用 503。

总结#

状态码是接口的第一层语义契约。核心记住三条:2xx 用准细分码、3xx 慎用且分清是否保持方法、4xx 分清 401/403 与 400/422、5xx 别把客户端错误塞进去。 设计时对照选用表,排查时先看首位定方向,再用 HTTP 请求测试器 复现验证。

立即体验:访问 HTTP 状态码查询

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

相关文章 智能推荐
1
HTTP状态码查询 - HTTP状态码大全及含义(1xx~5xx速查与排查)
HTTP工具 在线 HTTP 状态码查询:覆盖 1xx~5xx 常用状态码,每个状态码提供含义、常见原因与排查建议,支持输入即查。含 4xx vs 5xx、404 vs 403、502 vs 504 对比,开发排错、接口调试必备。
2
星点HTTP工具完整指南 - 11个在线HTTP请求调试工具导航(2026)
HTTP工具 星点HTTP工具系列完整指南:HTTP请求测试、状态码查询、Header解析/生成、请求转cURL、cURL解析、cURL转代码、Cookie/Set-Cookie解析、CORS检测/生成、Content-Type/MIME查询等 11 个在线工具一站式导航,全部本地处理不上传。
3
HTTP请求测试器 - 在线API接口调试工具(支持7种方法与复制cURL)
HTTP工具 在线 HTTP 请求测试器:支持 GET/POST/PUT/PATCH/DELETE/HEAD/OPTIONS 七种方法,自定义 Query、Headers、Body(JSON/Form/Raw)与 Auth(Bearer/Basic),一键查看状态码、响应头、响应体、耗时与大小,并复制为 cURL / Fetch。
4
Cookie解析器 - 在线解析cookie字符串为键值对
HTTP工具 在线 Cookie 解析器:把 document.cookie 或请求头里的 Cookie 字符串解析为 Name/Value 键值对表格,支持复制与数量统计,空值标注。快速看清携带了哪些 Cookie。
5
CORS检测/生成器 - 在线分析跨域配置与生成CORS Header
HTTP工具 在线 CORS 检测与生成器:分析 Access-Control-* 响应头识别跨域配置问题(如 Allow-Origin: * 与 Credentials 冲突),或表单式生成 CORS Header。前端开发跨域排查必备。
随机文章 随机推荐
公告
🎉 已升级 2.0 版本,欢迎使用。
分类
标签
站点统计
文章
197
分类
24
标签
747
总字数
334,099
运行时长
0 天
最后活动
0 天前

目录