资讯动态

HTTP状态码实战:分类语义、重试缓存与502/504排障

发布时间:2026/10/27 21:28:24 来源:尧图企业网站定制
1. 三位数字的首位本身就是一张排查地图线上告警响起来的时候值班的人最容易犯的错是盯着“红色”看而不是盯着“数字”看。我印象很深的一次是某个页面大面积白屏监控面板上 502 和 504 混在一起滚群里一半人说“上游服务挂了”另一半人说“网关超时了”吵了二十分钟。最后翻日志发现是连接池被打满一部分请求在拿连接时等到超时网关吐 504另一部分请求拿到了已经半死的连接回包解析失败网关吐 502。两个码一个根因。如果一开始就按 HTTP 响应码的首位分类拆开看这件事能省下十五分钟。HTTP 响应码是三位十进制数字很多人把它当成“给用户看的错误编号”其实它的设计逻辑严谨得多第一位数字定义了这一类响应的语义归属后两位才是细分。1xx 表示连接还在协商请求没走完2xx 表示请求被成功接收、理解并接受3xx 表示客户端需要再做一次动作才能拿到结果4xx 表示错误出在请求这一侧5xx 表示错误出在服务端这一侧。这套分类不是学院派洁癖它直接决定了中间件的行为。最实用的一条推论是4xx 重试没有意义5xx 重试可能有意义。因为 4xx 的语义是“这个请求本身有问题”你把一模一样的请求再发十遍服务端还是会拒。5xx 的语义是“服务端在处理时出了状况”换个时间点、换台机器可能就成功了。客户端 SDK 的重试策略、网关的熔断规则、监控的告警收敛全都建立在这条推论上。我见过不少自研 RPC 框架把重试做成“只要失败就重试三次”结果参数校验失败也重试白白放大了三倍流量把下游打得雪上加霜。1.1 状态码是写给机器看的契约不是写给用户看的文案这句话值得展开。状态码的第一消费方从来不是人而是缓存、代理、重试器、监控采集器和浏览器。缓存组件会依据状态码决定要不要存这份响应200、203、204、206、300、301、404、405、410、414、501 这些在规范里属于“可被启发式缓存”的范围而 302、307 默认不缓存除非显式给了 Cache-Control。重试中间件会依据状态码判断是否退避。浏览器依据 301 决定要不要把跳转关系长期记住。你随手返回的一个 200可能让 CDN 把一份错误页缓存了半小时。所以写后端接口时有一个很朴素的判断标准你返回的这个码会不会让下游的自动化组件做出错误决策。如果接口明明是“创建失败参数缺失”却返回 200 加一个{code: 10001}那所有基于状态码做统计的监控大盘都是废的所有基于状态码做重试的客户端都在瞎跑。业务码可以有自己的体系但 HTTP 状态码这层“机器契约”不能糊弄。1.2 不认识的码要按类兜底而不是抛异常规范里明确要求客户端必须能处理未定义的状态码处理方式是按首位归到对应的类别用x00的语义兜底。比如收到 599应当按 5xx 处理而不是崩溃。这条要求在实际代码里被违反得极其普遍。我排查过一个移动端 App 的崩溃堆栈显示某个网络库在解析响应时对状态码做了严格白名单匹配遇到 429 直接走了 default 分支抛运行时异常。而服务端上个月刚上线限流返回 429 是正常行为。两边单测都过了因为各自的 mock 里都没有对方的码。一个稳妥的写法是把状态码处理拆成两层先按status / 100取整做归类决定是重试、是刷新凭证、是提示用户还是直接失败再在类内对已知的码做细化处理。这样即使服务端未来新增了 425、428 这类冷门码客户端也不会因为“没见过”而崩。2. 2xx 里的七个“成功”选错了会埋雷大部分人对 2xx 的认知停在 200实际规范里定义了一串语义不同的成功码。它们之间的差别不是学术问题而是直接影响前端行为、缓存行为和自动化测试断言的。我按实际项目里最常被用错的程度往下排。2.1 200 与 204有没有响应体决定了前端会不会踩空200 是最通用的成功码语义是“请求成功响应体里有你要的东西”。204 的语义是“请求成功但我不打算返回任何内容”规范里明确要求 204 响应不能带响应体连Content-Length都不该有有些实现会带Content-Length: 0属于兼容性妥协。它最适合 DELETE 成功、PUT 成功但无需回显、以及某些“打个标记”类的操作。用错 204 的典型后果是前端拿到空响应体去JSON.parse直接抛错。反过来把本该 204 的场景写成 200 加{success: true}看似无害但会让所有做“响应体是否为空”判断的通用中间件多走一遍解析日志体积也白白膨胀。我的经验是资源删除类接口优先 204除非你确实要回传被删对象的快照。2.2 201 与 Location创建成功要把地址交出去201 的语义是“请求成功并且导致了一个新资源的创建”。规范建议配合Location响应头给出新资源的地址。这个头在实际项目里被忽略的比例很高但它对调用方非常有用前端创建完订单可以直接拿到详情地址跳转不用自己拼 URL自动化测试可以直接断言Location是否指向可访问的资源。一个常见的错误是创建接口返回 200 并回传{id: 123}然后让前端自己拼/api/orders/123。只要路由规则改一次前缀所有前端拼接的地方全炸。返回Location: /api/orders/123把这件事收敛到服务端是更稳的做法。2.3 202 与异步受理告诉调用方“我收下了但还没做完”202 的语义是“请求已被接受处理但处理尚未完成最终结果未知”。它最适合异步任务提交类接口上传一个大文件触发转码、提交一个批量导出任务、发起一个需要排队的计算。返回 202 时应该给出一个查询进度的地址或者任务 ID让调用方知道去哪里看结果。这里有个容易忽略的细节202 不代表成功它只代表受理。如果调用方把 202 当成“已完成”后续流程会拿到空数据。我在一个数据同步项目里就被这个坑过上游返回 202 之后我方立刻去拉结果拉到的永远是空。正确姿势是轮询任务状态接口或者约定一个回调地址。2.4 206 与断点续传Range 请求的落地细节206 的语义是“服务端完成了对资源某一部分的请求”必须配合Content-Range头告诉客户端返回的是哪一段。它服务于视频拖动进度条、大文件断点续传、多线程下载这些场景。要跑通 206服务端至少要处理三件事识别请求里的Range: bytesstart-end校验范围是否合法越界要回 416并在响应里带上Content-Range、Accept-Ranges: bytes和正确的Content-Length。如果资源在传输过程中变了还要用ETag或Last-Modified配合If-Range做一致性校验否则客户端拼出来的文件是坏的。这块细节我建议直接看成熟静态文件服务的实现自己从零写很容易漏掉边界条件。其余几个成功码用得少但别混淆203 表示响应经过中间层转换不保证与原资源一致205 表示“重置内容”要求客户端清空表单之类的状态实践中几乎没人正确实现建议避开。状态码语义要点典型场景常见误用200成功且有响应体查询、更新并回显拿它当所有成功的默认值201已创建建议带 Location新增资源不带 Location让前端拼 URL202已受理结果未定异步任务提交被当成“已完成”204成功无响应体删除、无回显更新带了响应体导致前端解析报错206部分内容断点续传、视频拖动缺 Content-Range 导致拼接失败3. 3xx谁把 POST 变成了 GET谁又把缓存记了一辈子3xx 这一族是实际项目里误解最集中的地方。很多人以为重定向就是“换个地址再访问”但真正的差别在于方法会不会变、请求体会不会丢、这个跳转关系会被记多久。这三个维度决定了一次重定向是优雅的解耦还是一场难以回滚的事故。3.1 301 与 302 的历史包袱以及 307/308 的补救301 表示永久移动302 表示临时找到。规范原意是让客户端按原方法重新请求新地址但早期浏览器实现里收到 301/302 后会把 POST 强行改成 GET 再发请求体直接丢掉。这个行为后来被大量系统依赖成了事实标准于是规范只能另起炉灶307 表示临时重定向且必须保持原方法和请求体308 表示永久重定向且同样保持方法和请求体。所以选型逻辑很清楚涉及表单提交、文件上传这类带 body 的 POST 请求如果重定向的目的是“换个地址但语义不变”用 307 或 308如果只是想跳到一个结果页用 303 更准确。301 和 302 更适合 GET 场景比如域名迁移、页面搬迁。这里有个必须提醒的坑301 会被浏览器长期缓存且很难清除。用户访问过一次旧地址被 301 到新地址之后即使你把 301 撤掉改回正常响应用户的浏览器仍然可能直接跳到新地址。我见过一次配置失误把某个接口错误地配了 301回滚之后仍有一批用户持续报错最后只能靠换接口路径解决。临时性跳转没有十足把握就用 302 或 307别图“永久”两个字看着干净。3.2 303 See Other明确要求“去那边用 GET 取结果”303 的语义非常干脆不管原请求是什么方法客户端都应该用 GET 去访问Location指向的地址。它最贴切的场景是表单提交后的“提交成功页”——POST 提交完重定向到一个 GET 的结果页用户刷新不会重复提交。这套模式在服务端渲染的年代是标配现在做前后端分离少了但在一些后台系统、支付回跳流程里仍然好用。3.3 304 不是“没修改”这么简单协商缓存的三个前置条件304 的语义是“资源未修改你可以用本地缓存”。它不带响应体但可以带一些元数据头比如新的Cache-Control、ETag。要让 304 正确工作需要三方配合第一服务端在首次响应里给出验证器通常是ETag内容指纹或Last-Modified最后修改时间ETag精度更高优先用。第二客户端下次请求时带上If-None-Match或If-Modified-Since。第三服务端比对后一致则返回 304不一致则返回 200 加新内容。实际踩坑最多的是ETag的生成方式。有些框架默认用文件 inode 加修改时间生成多台机器部署时同一个文件在不同机器上的 inode 不同导致ETag不一致缓存命中率直接归零所有请求都穿透到源站。另一类坑是用了弱验证器W/...却没理解它的语义——弱验证器只保证语义等价不保证字节一致做 Range 请求时必须用强验证器。还有一点304 响应虽然没 body但状态码本身是可以被缓存的代理层看到 304 会更新自己缓存的元数据。如果你在前面套了一层 CDN源站返回 304 的行为会直接影响 CDN 的缓存新鲜度计算这块要跟缓存策略一起验证别只看浏览器表现。3.4 重定向实操中容易忽略的三件事第一是凭证丢失。跨域重定向时浏览器默认不会把Authorization头带到新地址如果新地址依赖这个头做鉴权会直接 401。正确做法是通过一次性的跳转票据放在 query 或短期有效的 cookie 里完成身份交接。第二是Location用相对路径还是绝对路径。规范允许相对路径浏览器能正确解析但某些老客户端和部分代理实现会有兼容问题。对外提供的公共接口我倾向于给绝对路径。第三是循环重定向。A 跳 B、B 跳 A浏览器会在若干次之后报错终止但服务端日志里看到的是一串 302很容易被误判成“流量突增”。给重定向加一个跳转次数上限或者用带签名的跳转参数能快速定位这类问题。4. 4xx把“请求方的问题”表达准确比一律返回 500 有价值得多4xx 这一族最容易被偷懒对待——很多团队的做法是“凡是业务异常统统包成 200 加错误码”或者“凡是出错就 500”。这两种做法都会让排查成本翻倍。4xx 的价值在于它精确地告诉调用方问题在你的请求里你改请求就能解决别来找我。把这句话说清楚能省掉大量无效的沟通和无效的重试。4.1 401 与 403 的分界线你是谁和你能做什么这两个码混用是重灾区。401 的语义是“未认证”——我不知道你是谁请先提供凭证。规范要求 401 响应必须带WWW-Authenticate头告诉客户端该用哪种方式认证。403 的语义是“已认证但禁止访问”——我知道你是谁但你没有权限做这件事。判断方法很简单如果用户重新登录一次问题会不会解决。会解决就是 401不会解决就是 403。用户 A 去删用户 B 的订单A 登录状态完全正常重新登录一百次也没用这就是 403。令牌过期导致所有接口都拒重新登录就好这是 401。实践中还有一个细节令牌缺失和令牌无效都应该归到 401而不是一个 401 一个 403。有些团队把“没带 token”返回 403导致客户端无法触发“跳转登录页”的自动逻辑用户只能手动刷新。4.2 400、415、422三种不同性质的“请求有问题”400 是笼统的“请求格式有问题”服务端无法解析。它适合语法级错误JSON 格式不对、必填参数缺失、参数类型不对。415 专门针对Content-Type不被支持。比如接口只接受application/json客户端发来text/plain应该回 415而不是 400。这个区分对客户端排查很有价值因为它直接指向“你该改请求头”。422 的语义是“请求格式正确但内容在语义上无法处理”。典型的场景是业务规则校验失败金额必须大于 0、开始时间不能晚于结束时间、邮箱格式不合法。这类错误 JSON 能解析、字段类型也对就是值不合理。我的经验是语法错误用 400媒体类型错误用 415业务校验错误用 422。这套分工能让前端在统一拦截器里做出差异化处理——400 和 415 属于“代码写错了”值得报警422 属于“用户填错了”应该把提示语展示给用户。4.3 404、410、405、501四个容易被混为一谈的码404 表示目标资源不存在。它有一个隐含语义常被忽略服务端可以返回 404 来隐藏资源存在但无权访问的事实避免泄露信息。安全场景下这是正当用法。410 表示资源曾经存在但已被永久移除。它的实用价值在于告诉客户端“别再来了”搜索引擎也会据此更快地把页面从索引里剔除。做内容下线功能时410 比 404 更准确。405 表示方法不被允许响应里必须带Allow头列出支持的方法。比如接口只支持 GET客户端发了 DELETE应该回 405 加Allow: GET, POST而不是 404。这个细节能让调试变得非常快我排查过一个“接口明明存在却报 404”的问题根因是网关把不支持的 method 直接映射成 404 了导致前端一直在检查 URL 拼写。501 表示方法未被服务端实现。它和 405 的区别在于405 是“这个资源不支持这个方法”501 是“服务端根本不认识这个方法”。501 属于 5xx 家族这点很多人记错。4.4 409、412、428并发更新场景的三件套409 表示请求与资源当前状态冲突。最典型的场景是版本号乐观锁客户端提交更新时带了旧版本号服务端发现当前版本已经变了回 409让客户端先拉最新数据再决定。412 用于条件请求前置条件不满足。比如客户端带If-Match: etag-v1去更新服务端发现当前 ETag 已经是 v2回 412。它和 409 的区别在于412 是 HTTP 层条件请求机制的一部分409 更偏业务语义。428 表示服务端要求请求必须带条件头。它的用途是防止“丢失更新”——服务端强制要求所有更新请求带上If-Match没带的直接拒逼客户端做版本检查。这个码在实际项目里用得少但对数据一致性要求高的场景是个很好的保护开关。4.5 413、414、431三种“太大了”别混着用413 是请求体过大网关的上传大小限制触发时通常返回它。414 是 URL 过长常见于 GET 请求把大量参数塞进 query或者Referer特别长。431 是请求头字段过大通常是 cookie 太多太大导致的。这三者经常被统一成 400 返回结果是排查时完全看不出方向。客户端做重试或降级时这三种情况的应对策略也不一样413 要分片上传414 要改成 POST431 要清理 cookie。4.6 429限流场景必须有配套头429 表示请求过多。它最大的价值在于配合Retry-After头告诉客户端多久之后可以再试。如果只返回 429 不给时间客户端只能瞎猜常见的结果是立刻重试反而把限流压力放大。限流响应里我建议一并给出配额信息比如剩余额度、窗口重置时间。这些头不是规范强制的但对客户端做自适应退避极有帮助。另外要注意429 是 4xx按“4xx 重试无意义”的结论它是个例外——它明确表示“稍后可以重试”所以客户端的重试分类逻辑里必须给 429 单独开一个分支走带退避的重试。状态码语义一句话判断方法401未认证重新登录能解决吗能403已认证无权限重新登录能解决吗不能409与资源当前状态冲突是否涉及版本或状态机412条件请求前置条件失败请求是否带了 If-Match 类头422语义校验失败请求能解析但值不合法429限流响应是否带 Retry-After5. 5xx分清“自己挂了”和“上游挂了”排查效率差三倍5xx 是告警的主力来源但同样是 5xx根因可能在完全不同的层次。500 是应用自己抛的502 和 504 通常来自网关503 可能是主动降级501 是方法层面的缺失505 是协议版本不匹配。如果日志平台只按“5xx”聚合你看到的是一条混在一起的曲线什么都说明不了。5.1 500 是兜底不是方案500 的语义是“服务端遇到未预期的情况无法完成请求”。它是最后一道防线不是分类工具。如果一个接口里到处throw new Error()然后在全局异常处理器里统一转 500你的监控就失去了细分能力所有业务异常和真正的程序 bug 挤在同一条线上。我的做法是把异常分三层可预期的业务异常映射到对应的 4xx依赖外部服务失败映射到 502 或 504剩下的才归到 500并且 500 必须在日志里带上完整的堆栈和请求标识。这样 500 的曲线才有意义——它应该接近零一旦抬头就是真 bug。5.2 502 与 504一个回包不对一个等不到回包这是最容易混淆的一对。502 的语义是“网关或代理从上游收到了无效响应”。注意是“收到了”只是内容不对劲上游进程崩了导致连接被重置、上游返回了残缺的 HTTP 报文、上游返回了网关无法解析的东西。504 的语义是“网关等待上游响应超时”压根没等到回包。用一句生活化的比喻502 是你托人买东西对方给回来一袋不知道是什么的东西504 是你托人买东西等到约定时间人还没回来。这个区分对排查方向的影响巨大。502 要去查上游进程的健康状态、连接是否被中间设备干扰、报文是否符合协议504 要去查超时配置和上游的处理耗时。我遇到过一批 502最后定位到上游应用的 keep-alive 超时设置短于网关的连接复用时间——网关以为连接还活着把请求发过去上游已经把这个连接关了并回了 RST网关就报 502。这类问题在 504 的方向里是永远查不到的。5.3 503 与 Retry-After主动告知“我暂时不行”503 的语义是“服务端当前无法处理请求通常是临时的”。它适合主动降级的场景服务正在发布、数据库连接池耗尽触发保护、依赖的存储不可用。配合Retry-After头告诉客户端多久后再来比让客户端盲目重试友好得多。要注意 503 不应该用来掩盖真正的故障。有些团队在应用启动时先返回 503 直到预热完成这个用法是合理的但如果一个接口长期返回 503说明容量规划出了问题需要告警而不是静默容忍。5.4 网关上这几种码的来源得看响应头指纹排查时第一件事是确认这个码是谁吐出来的。看响应头里的Server、Via、以及各个网关自带的标识头能快速定位。有时候你以为是应用返回的 502其实是中间某个代理层返回的应用日志里干干净净什么都没有白白浪费半小时翻日志。另一个技巧是对比不同入口的响应。内网直连应用返回 200走网关返回 502那问题基本锁定在网关到应用这一段。这一步不用改任何配置几分钟就能缩小一半范围但很多人在慌乱中直接跳过了。6. 一次 502 与 504 混报的完整复盘链路我把它拆成可复用的四步因为这套流程我在后来的几次故障里反复用到命中率很高。6.1 第一步确认码的发出方先看响应头再看访问日志的位置。如果响应头里有明显的网关标识说明码是网关生成的应用侧的访问日志里可能记录的是 200 或者压根没有记录。这时候去翻网关的 error log通常会明确写出 upstream 的地址和失败类型比如连接被拒、读超时、响应头解析失败。如果响应头里没有网关标识码可能是应用自己返回的。这时候去应用日志里搜请求 ID看有没有对应的异常堆栈。6.2 第二步用命令行工具分步复现绕过网关直连应用重复同样的请求。直连正常而走网关异常问题在中间层直连也异常问题在应用。这一步能砍掉一半的怀疑对象。复现时要注意带上和真实请求一致的头部尤其是Host、Content-Type、Content-Length和认证信息。我见过一个问题只在带特定User-Agent时出现原因是网关对某些 UA 做了特殊处理不带这个头永远复现不出来。6.3 第三步把超时链路摆出来对齐超时是个层级结构客户端超时、网关连接上游的超时、网关等待上游响应的超时、应用内部调用下游的超时、下游自己的处理超时。这五层里只要有一层比它的上一层还长就会出现“上层已经放弃了下层还在干活”的情况表现为上层报超时、下层日志显示请求最终成功。一个合理的配置原则是由外向内逐层递减客户端超时 网关超时 应用内下游调用超时 下游实际处理时间。这样任何一层超时都能在它自己的层面被捕获并返回明确的码而不是层层穿透最后变成一个语焉不详的 504。6.4 第四步看连接池指标而不是只看 QPS那次故障最后定位到连接池起因是某个慢查询把连接占满新请求排队等连接等到网关超时就返回 504而排队中被复用的连接如果已经被对端关闭请求发出去就收不到正常响应表现为 502。QPS 曲线当时很平稳完全看不出问题只有连接池的等待队列长度和活跃连接数在飙升。所以 5xx 抬头时除了看流量和错误率一定要把连接池指标、线程池队列长度、GC 停顿时间一起拉出来。这几个指标能解释大部分“流量没涨但错误率涨了”的诡异现象。7. 接口设计里HTTP 状态码和业务错误码怎么分工这是团队协作里最容易吵架的话题。我的观点很明确两层码各司其职不要互相替代。HTTP 状态码负责表达“这次请求在协议层面的结果”业务错误码负责表达“在业务语义上具体是哪一条规则没过”。前者给基础设施看后者给业务代码和用户看。7.1 两层码的职责边界HTTP 状态码要被缓存、网关、监控、负载均衡消费它的取值必须收敛在规范定义的范围里语义必须稳定。业务错误码面向调用方的业务逻辑可以自由扩展可以有自己的编号体系、文案映射和多语言支持。一个健康的响应结构大致是这样HTTP 层返回准确的 4xx 或 5xx响应体里带上业务错误码和可读的提示信息。这样网关能正确统计错误率客户端能按状态码做统一处理业务代码能按业务码做精细化分支。反过来“所有请求都返回 200用 body 里的 code 表示成败”这种做法代价是监控大盘失效、CDN 缓存策略失效、客户端重试逻辑失效、浏览器和工具的调试信息失效。它在某些历史系统里存在是有原因的早期某些客户端对非 2xx 处理不完善但新项目没有理由继续这么干。7.2 常见业务场景到状态码的映射下面这张表是我自己在项目里常用的对照可以直接拿去改成团队规范。业务场景推荐状态码补充说明查询成功200空结果也是 200别用 404创建成功201带 Location更新成功无回显204不带响应体删除成功204幂等删除重复调用也返回 204参数格式错误400附字段级错误信息未登录或令牌失效401带 WWW-Authenticate已登录无权限403不要暴露资源是否存在资源不存在404列表查询为空不算 404方法不支持405必须带 Allow版本冲突409附当前版本号业务规则校验失败422附具体规则标识触发限流429带 Retry-After依赖服务异常502附上游标识服务暂时不可用503带 Retry-After上游超时504记录上游耗时7.3 幂等与状态码的配合容易被忽略DELETE 的幂等性经常被误解成“重复删除要返回 404”。实际上幂等指的是“执行一次和执行多次对资源状态的最终影响相同”返回码可以不同。我的习惯是第一次删除返回 204重复删除也返回 204因为对调用方来说结果是一样的——资源已经不在了。这样客户端不需要区分“删成功”和“本来就没有”逻辑更简单。PUT 的语义是“用请求体整体替换目标资源”它天然幂等。如果资源不存在可以创建返回 201也可以拒绝返回 404取决于接口约定但必须在文档里写清楚。PATCH 的语义是部分更新不保证幂等这一点在设计批量操作接口时要特别注意。8. 几个冷门但值得知道的码最后聊几个平时用不上、但遇到时能省下不少时间的码。它们不属于“必须掌握”但知道存在排查时就不会把正常行为当成故障。8.1 100 与 103连接协商阶段的两个信号100 出现在客户端发送Expect: 100-continue的场景。客户端先发头部问服务端“我要传一个大文件你收不收”服务端回 100 表示“收继续发”客户端才开始传 body。这个机制能在服务端拒收时省掉一次大文件传输。排查上传相关问题时如果在抓包里看到 100不用紧张它是正常的中间状态。103 用于在最终响应之前提前推送一些提示信息最典型的用法是把关键静态资源的预加载链接提前告诉浏览器让浏览器在服务端还在生成页面的同时就开始下载资源。它对首屏性能有实际帮助但需要服务端和客户端都支持配置不当的话抓包里会出现多个 103属于正常现象。8.2 421、425、426连接层面的三个提示421 表示请求被发到了无法产生响应的服务器常见于 HTTP/2 的连接复用场景——同一个连接上承载了多个域名的请求如果服务端没有为某个域名配置证书就会回 421让客户端换一个连接重试。425 表示服务端担心请求被重放要求客户端稍后重试。它出现在 TLS 早期数据的场景里日常几乎碰不到但如果你在日志里看到它说明有安全中间件在介入。426 表示客户端需要升级协议。最典型的是服务端只接受加密连接客户端用了明文服务端回 426 并在Upgrade头里说明要求。它比直接断开连接友好得多客户端能据此给出明确提示。8.3 有些码知道但别乱用418 是个玩笑性质的码某些框架拿它做彩蛋。生产环境不要用因为它会让所有基于状态码做统计的工具出现一个无法归类的项。自定义 6xx 之类的码规范允许扩展但所有中间设备、日志系统、客户端 SDK 都可能不认识。真要表达业务语义放进响应体的业务码里别去动 HTTP 状态码这一层。还有一个常见做法是“用 500 表示业务失败”。这个习惯的来源往往是早期框架的默认异常处理。它的代价是让 500 这条曲线彻底失去意义真正的程序 bug 被淹没在业务失败里。如果历史代码已经这么写了迁移时可以先在网关层做一层映射把已知的业务失败码改写成 4xx逐步收敛而不是一次性大改。我个人在实际操作中的体会是把状态码用对这件事短期看是“多写了几行分支”长期看是给整个链路的自动化能力打地基。缓存、重试、熔断、监控、告警、调试工具全都依赖这一层语义的准确性。反过来如果这一层是糊的上面每加一个组件都要额外写一堆特殊判断来兜底成本会以复利的方式滚上去。所以每次设计新接口时花十分钟把状态码对照表过一遍是性价比极高的一件事。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑