HTTP 状态码是服务器对客户端请求的"暗号"。无论是前端调试、后端接口开发还是运维排障,看懂状态码都是基本功。本文按 1xx~5xx 分类,逐一讲解常用状态码的含义、典型场景、调试方法,并附带 curl 测试命令和 Nginx/Express 配置示例。
一、状态码总览
| 类别 | 范围 | 含义 | 常见状态码 |
|---|---|---|---|
| 1xx | 100 ~ 103 | 信息响应——请求已收到,继续处理 | 100, 101 |
| 2xx | 200 ~ 226 | 成功——请求已成功处理 | 200, 201, 204, 206 |
| 3xx | 300 ~ 308 | 重定向——需要进一步操作 | 301, 302, 304, 307, 308 |
| 4xx | 400 ~ 451 | 客户端错误——请求有问题 | 400, 401, 403, 404, 405, 429 |
| 5xx | 500 ~ 511 | 服务端错误——服务器处理失败 | 500, 502, 503, 504 |
二、1xx:信息响应
100 Continue
客户端发送带 Expect: 100-continue 头的请求时,服务器返回 100 表示"可以继续发送请求体"。常用于大文件上传前先探测服务器是否愿意接收。
# curl 模拟 100-continue
curl -X POST -H "Expect: 100-continue" \
-H "Content-Type: application/json" \
-d '{"large":"payload"}' https://api.example.com/upload101 Switching Protocols
WebSocket 握手时,服务器返回 101 表示协议切换。
# WebSocket 升级请求
curl -i -N -H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
http://localhost:8080
# 响应:
# HTTP/1.1 101 Switching Protocols
# Upgrade: websocket
# Connection: Upgrade三、2xx:成功响应
200 OK
请求成功,最常见。GET 返回资源,POST 返回处理结果。
curl -i https://api.example.com/users/1
# HTTP/1.1 200 OK201 Created
POST 创建资源成功后返回,通常会在 Location 头中携带新资源的 URL。
curl -i -X POST \
-H "Content-Type: application/json" \
-d '{"name":"张三"}' https://api.example.com/users
# HTTP/1.1 201 Created
# Location: /users/42Express 示例:
app.post('/users', async (req, res) => {
const user = await User.create(req.body);
res.status(201)
.location(`/users/${user.id}`)
.json(user);
});204 No Content
请求成功但无返回体。常见于 DELETE 或 PUT 更新操作。
curl -i -X DELETE https://api.example.com/users/42
# HTTP/1.1 204 No Content206 Partial Content
断点续传、分片下载。配合 Range 头使用。
# 只下载前 1024 字节
curl -i -H "Range: bytes=0-1023" https://example.com/video.mp4
# HTTP/1.1 206 Partial Content
# Content-Range: bytes 0-1023/10485760
# Content-Length: 1024四、3xx:重定向
301 Moved Permanently(永久重定向)
资源已永久迁移到新 URL。浏览器会缓存,搜索引擎会更新索引。
302 Found(临时重定向)
资源临时移动。浏览器不缓存,下次仍请求原 URL。
| 特性 | 301 永久重定向 | 302 临时重定向 |
|---|---|---|
| 浏览器缓存 | 会缓存 | 不缓存 |
| SEO 影响 | 权重转移给新 URL | 权重保留在原 URL |
| 请求方法变化 | POST 可能变 GET | POST 可能变 GET |
| 使用场景 | 域名迁移、HTTPS 强制 | 活动页、维护页跳转 |
⚠️ 注意:301/302 在浏览器中有个著名坑——POST 请求被重定向后可能变成 GET 请求。如果希望保持请求方法不变,使用 307/308。
307 Temporary Redirect / 308 Permanent Redirect
与 302/301 的区别:严格保持请求方法和请求体不变。
# Nginx:301 永久重定向到 HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
# Nginx:302 临时维护页面
location /app {
return 302 /maintenance.html;
}
# Nginx:308 保持 POST 方法
location /api/v1 {
return 308 /api/v2$request_uri;
}304 Not Modified
缓存验证。客户端携带 If-None-Match(ETag)或 If-Modified-Since 请求,服务器判断资源未变化则返回 304,客户端使用本地缓存。
curl -i -H "If-None-Match: \"abc123\"" https://example.com/style.css
# HTTP/1.1 304 Not ModifiedExpress 中启用 ETag:
// Express 默认启用 ETag,也可手动控制
app.set('etag', 'strong'); // 或 'weak'
app.get('/data', (req, res) => {
const data = { time: Date.now() };
// Express 自动生成 ETag 并处理 304
res.json(data);
});五、4xx:客户端错误
400 Bad Request
请求报文语法错误,如 JSON 格式不正确、参数缺失等。
curl -i -X POST \
-H "Content-Type: application/json" \
-d "这不是JSON" https://api.example.com/users
# HTTP/1.1 400 Bad Request401 Unauthorized
未认证——需要提供有效凭证。常见于未登录或 Token 过期。
curl -i https://api.example.com/admin
# HTTP/1.1 401 Unauthorized
# WWW-Authenticate: Bearer realm="api"403 Forbidden
已认证但无权限——"我知道你是谁,但你不能访问这个资源"。
| 状态码 | 含义 | 类比 |
|---|---|---|
| 401 Unauthorized | 没带证件 | 进大楼没刷卡 |
| 403 Forbidden | 证件不对口 | 刷了卡但没权限进这个房间 |
404 Not Found
资源不存在。注意:RESTful 接口中,有时也返回 404 来隐藏资源是否存在(避免枚举攻击)。
curl -i https://api.example.com/users/99999
# HTTP/1.1 404 Not Found405 Method Not Allowed
HTTP 方法不允许。比如对只读接口发 POST。
curl -i -X POST https://api.example.com/health
# HTTP/1.1 405 Method Not Allowed
# Allow: GET, HEAD429 Too Many Requests
触发频率限制。响应头中通常包含 Retry-After 或 X-RateLimit-* 信息。
# 模拟触发限流
for i in $(seq 1 100); do
curl -s -o /dev/null -w "%{http_code}\n" https://api.example.com/data &
done
# HTTP/1.1 429 Too Many Requests
# Retry-After: 60
# X-RateLimit-Limit: 100
# X-RateLimit-Remaining: 0
# X-RateLimit-Reset: 1720950000Express 限流中间件:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 分钟
max: 100, // 最多 100 次
standardHeaders: true,
legacyHeaders: false,
message: { error: '请求过于频繁,请稍后再试' }
});
app.use('/api/', limiter);Nginx 限流:
# 限流区域:每秒 10 个请求
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
location /api/ {
limit_req zone=mylimit burst=20 nodelay;
proxy_pass http://backend;
}
}六、5xx:服务端错误
500 Internal Server Error
服务端代码异常(未捕获的错误)。
// ❌ 危险:裸奔的错误处理
app.get('/data', async (req, res) => {
const result = await riskyOperation(); // 可能抛异常 → 500
res.json(result);
});
// ✅ 安全:全局错误处理中间件
app.use((err, req, res, next) => {
console.error('服务器错误:', err.stack);
res.status(500).json({
error: '服务器内部错误',
requestId: req.id // 方便关联日志排查
});
});502 Bad Gateway
网关或代理服务器收到上游无效响应。常见于:
- 后端服务挂了
- 后端返回了格式错误的响应
- 反向代理配置的 upstream 不可达
# 自定义 502 错误页
error_page 502 /502.html;
location = /502.html {
root /usr/share/nginx/html;
}503 Service Unavailable
服务器暂时不可用——过载或维护中。应返回 Retry-After 头。
curl -i https://example.com
# HTTP/1.1 503 Service Unavailable
# Retry-After: 3600504 Gateway Timeout
网关超时——上游服务器响应太慢。
# 延长上游超时
location /slow-api/ {
proxy_pass http://backend;
proxy_read_timeout 120s;
proxy_connect_timeout 10s;
}七、浏览器 DevTools 排查技巧
Network 面板快速诊断
- 打开 DevTools → Network 标签
- 刷新页面,按 Status 列排序
- 红色状态码(4xx/5xx)重点关注
关键检查项
| 现象 | 排查方向 |
|---|---|
| 大量红色 404 | 静态资源路径错误、CDN 配置问题 |
| 间歇性 502/504 | 后端负载过高、连接池耗尽 |
| AJAX 请求 401 | Token 过期、Cookie 丢失 |
| 跨域请求失败 | CORS 头缺失,看 Console 的 CORS 错误 |
| 请求发出后立即 400 | 检查 Request Payload 格式 |
curl 调试三板斧
# 1. 只看状态码
curl -o /dev/null -s -w "%{http_code}\n" https://example.com
# 2. 看完整响应头 + 体
curl -i https://example.com
# 3. 看详细过程(含 DNS、TCP、TLS 握手时间)
curl -w "@curl-format.txt" -o /dev/null -s https://example.com
# curl-format.txt 内容:
# time_namelookup: %{time_namelookup}\n
# time_connect: %{time_connect}\n
# time_appconnect: %{time_appconnect}\n
# time_pretransfer: %{time_pretransfer}\n
# time_redirect: %{time_redirect}\n
# time_starttransfer: %{time_starttransfer}\n
# time_total: %{time_total}\n八、速查表
| 状态码 | 含义 | 一句话记忆 |
|---|---|---|
| 200 | OK | 一切正常 |
| 201 | Created | 新建成功,去 Location 找 |
| 204 | No Content | 成功但没话说 |
| 301 | Moved Permanently | 搬家了,新地址记好 |
| 302 | Found | 临时换个地方 |
| 304 | Not Modified | 用你手里的缓存 |
| 400 | Bad Request | 你发的啥我看不懂 |
| 401 | Unauthorized | 你没带证件 |
| 403 | Forbidden | 有证件也没用 |
| 404 | Not Found | 找不到这个 |
| 429 | Too Many Requests | 你太快了,慢点 |
| 500 | Internal Server Error | 我炸了 |
| 502 | Bad Gateway | 上游炸了 |
| 503 | Service Unavailable | 在维护,等会儿再来 |
| 504 | Gateway Timeout | 上游响应太慢了 |
总结
- 2xx — 成功了,按语义区分 200/201/204/206
- 3xx — 重定向,301/302 改变方法体,307/308 保留方法体,304 用于缓存
- 4xx — 你的问题,401 vs 403 分清认证和授权
- 5xx — 我的问题,502/504 通常是反向代理层的锅
掌握这些状态码,配合 curl 和浏览器 DevTools,排障效率提升一个数量级。