# 响应状态码
30 秒速记
- 三位数,看首位分大类:
1xx还没完 /2xx成功 /3xx重定向或用缓存 /4xx客户端的问题 /5xx服务器的问题 - 常用:
200、204无响应体、206部分内容;301永久、302临时、304用本地缓存 4xx:400参数不对、401没登录、403没权限、404没这个资源5xx:500代码炸了、502网关拿到上游坏响应、503暂时不可用、504等上游超时- 原因短语(
OK、Not Found)可以随便改,HTTP/2里干脆没了,代码只认数字 fetch遇到404、500不会进catch,要自己判断response.ok
状态码是服务器对这次请求处理结果的一句话总结,看首位数字就能先判断是谁的问题。 2xx 成功,3xx 让你去别处拿或者直接用缓存,4xx 是请求本身有问题,5xx 是服务器没处理好。写代码时有几个坑:204 没有响应体,无脑 response.json() 会报错;304 是缓存命中,不是跳转;fetch 只在网络断了才 reject,拿到 500 也是 resolve,必须自己检查 response.ok。另外接口统一返回 200、错误塞在 body.code 里的设计很常见,这时协议层成功不代表业务成功,监控要分开统计。
- 状态码在响应报文里表示了服务器对请求的处理结果;
- 状态码后的原因短语是简单的文字描述,可以自定义;
- 状态码是十进制的三位数,分为五类,从
100到599; 2××类状态码表示成功,常用的有200、204、206;3××类状态码表示重定向,常用的有301、302、304;4××类状态码表示客户端错误,常用的有400、403、404;5××类状态码表示服务器错误,常用的有500、501、502、503

原理拆解: 状态码位于响应起始行,是服务器对本次 HTTP 处理结果的协议级分类。1xx 表示中间状态,2xx 表示请求已成功处理,3xx 涉及后续定位或缓存复用,4xx 表示当前请求存在客户端侧问题,5xx 表示服务器未能正常完成处理。客户端应以数字状态码及响应语义为准,不能依赖可被修改、甚至在 HTTP/2 和 HTTP/3 中不再以传统原因短语形式传输的说明文字。
最小验证: 输入四个本地路径,验证客户端能够收到 200、204、404 和 500,同时观察 204 没有响应体。以下 JavaScript 可直接由 Node.js 运行。
const http = require('node:http');
const server = http.createServer((req, res) => {
if (req.url === '/ok') {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('saved');
} else if (req.url === '/empty') {
res.writeHead(204);
res.end();
} else if (req.url === '/error') {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('internal error');
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('not found');
}
});
server.listen(0, async () => {
const { port } = server.address();
for (const path of ['/ok', '/empty', '/missing', '/error']) {
const response = await fetch(`http://127.0.0.1:${port}${path}`);
console.log(path, response.status, JSON.stringify(await response.text()));
}
server.close();
});
关键行是 writeHead,它确定响应状态;预期依次打印 200 "saved"、204 ""、404 "not found" 和 500 "internal error"。fetch 对 404、500 不会自动抛出异常,调用方必须检查 response.ok 或 response.status。
边界与排查: 204 成功但不携带正文,206 只表示部分内容;304 主要用于条件请求的缓存复用,不应简单理解为页面跳转。401、403 和 404 的含义也不同,分别偏向认证、拒绝访问和资源不存在。业务接口即使返回 200,正文仍可能表达业务失败,因此协议状态与业务状态需要分层判断;排查时应同时核对状态码、响应头、正文及重定向链。
面试官追问
追问 1下载服务返回 206,监控因为不是 200 就记成失败,怎么改?
按大类判断成功,status >= 200 && status < 300 或者直接用 response.ok。206 是范围请求的正常结果,视频播放、断点续传每一段都是它,写死 === 200 会误报一大片。
追问 2批量删除接口返回 204,前端统一 response.json() 后进了异常分支,谁的锅?
前端封装的锅。204 明确表示成功且没有响应体,对空字符串做 JSON.parse 当然会抛错。封装里先判断状态再解析:
追问 3fetch 拿到 500,catch 里一条日志都没有,是浏览器吞了异常吗?
不是。fetch 的约定就是只要拿到了响应,不管 404 还是 500 都 resolve,只有断网、跨域被拦这类网络层失败才 reject。要在 then 里判断 if (!res.ok) throw new Error(res.status),axios 才是默认把非 2xx 当错误抛出来的。
追问 4301、302、307、308 都是跳转,差在哪?
301、308 是永久,浏览器和搜索引擎会记住新地址;302、307 是临时。另一个区别是方法:307、308 保证原来是 POST 跳过去还是 POST,301、302 实际上浏览器会把 POST 改成 GET。表单提交后要换地址又不想丢请求体,就用 307。
追问 5告警只覆盖 500,一次故障全是 502 和 503,没报出来,怎么调?
告警按 5xx 整类配,再按具体码区分来源。502 通常是上游进程挂了或者返回了坏响应,503 常见于限流、发布摘流量,504 是网关等上游超时。这几个往往比 500 更说明出了大问题,漏掉就是告警盲区。
