返回首页

说说HTTP常见的状态码有哪些,适用场景

问题解析

HTTP状态码是服务器对客户端请求的响应结果标识,面试官通过这个问题考察候选人对HTTP协议的掌握程度,以及能否正确理解和使用各种状态码。

核心概念

HTTP状态码概述

HTTP状态码(Status Code)是3位数字,表示服务器对请求的处理结果。状态码分为5个类别:

类别 范围 含义
1xx 100-199 信息性状态码(Informational)
2xx 200-299 成功状态码(Success)
3xx 300-399 重定向状态码(Redirection)
4xx 400-499 客户端错误状态码(Client Error)
5xx 500-599 服务器错误状态码(Server Error)

状态码格式

HTTP/1.1 200 OK
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF

详细解答

1xx 信息性状态码

表示请求已被接收,需要继续处理。

100 Continue

客户端                    服务器
   |---- POST (Expect: 100-continue) --->|
   |                                     |
   |<----------- 100 Continue -----------|
   |                                     |
   |----------- 请求体 ----------------->|
   |                                     |
   |<----------- 200 OK -----------------|

场景: 客户端发送大请求体前,询问服务器是否愿意接收

使用:

import requests

headers = {'Expect': '100-continue'}
response = requests.post(url, headers=headers, data=large_data)

101 Switching Protocols

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade

场景: 服务器同意切换协议(如HTTP升级到WebSocket)

2xx 成功状态码

表示请求已被成功接收、理解和处理。

200 OK

HTTP/1.1 200 OK
Content-Type: application/json

{
  "status": "success",
  "data": { ... }
}

场景: 请求成功,返回所请求的资源

使用范围:

  • GET请求:返回资源
  • POST请求:返回操作结果
  • PUT/PATCH请求:返回更新后的资源
  • DELETE请求:返回删除确认

201 Created

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

{
  "id": 123,
  "name": "张三",
  "created_at": "2024-01-01T00:00:00Z"
}

场景: 资源创建成功

使用:

  • POST创建资源后返回
  • 应包含Location头部指向新资源

202 Accepted

HTTP/1.1 202 Accepted
Location: /api/tasks/456

{
  "task_id": 456,
  "status": "processing",
  "message": "请求已接受,正在处理"
}

场景: 请求已接受,但尚未处理完成(异步处理)

使用:

  • 耗时操作(如批量处理、视频转码)
  • 返回任务ID供查询进度

204 No Content

HTTP/1.1 204 No Content

场景: 请求成功,但无返回内容

使用:

  • DELETE删除成功
  • PUT/PATCH更新成功(无需返回资源)
  • 预检请求响应

206 Partial Content

HTTP/1.1 206 Partial Content
Content-Range: bytes 0-999/5000
Content-Length: 1000

[部分数据]

场景: 成功处理范围请求(断点续传、视频分段加载)

使用:

GET /video.mp4 HTTP/1.1
Range: bytes=0-999

HTTP/1.1 206 Partial Content
Content-Range: bytes 0-999/5000

3xx 重定向状态码

表示需要客户端采取进一步操作才能完成请求。

301 Moved Permanently

HTTP/1.1 301 Moved Permanently
Location: https://new-domain.com/page

场景: 资源永久移动到新的URL

特点:

  • 搜索引擎会更新索引
  • 浏览器会缓存重定向
  • 后续请求直接访问新地址

302 Found

HTTP/1.1 302 Found
Location: https://example.com/login

场景: 资源临时移动到新的URL

注意:

  • 历史上实现不规范,有歧义
  • 部分客户端会将POST改为GET(不符合规范)

304 Not Modified

HTTP/1.1 304 Not Modified
ETag: "33a64df5"
Cache-Control: max-age=3600

场景: 资源未修改,使用缓存版本

使用:

GET /style.css HTTP/1.1
If-None-Match: "33a64df5"

HTTP/1.1 304 Not Modified

307 Temporary Redirect

HTTP/1.1 307 Temporary Redirect
Location: https://example.com/new-path

场景: 临时重定向,保持请求方法不变

与302的区别:

  • 307要求保持原请求方法(POST仍是POST)
  • 302可能被实现为方法改变

308 Permanent Redirect

HTTP/1.1 308 Permanent Redirect
Location: https://example.com/new-path

场景: 永久重定向,保持请求方法不变

与301的区别:

  • 308要求保持原请求方法
  • 301可能被实现为方法改变

4xx 客户端错误状态码

表示客户端请求有误,服务器无法处理。

400 Bad Request

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "Bad Request",
  "message": "请求参数格式错误",
  "details": {
    "email": "邮箱格式不正确"
  }
}

场景: 请求语法错误或参数无效

使用:

  • 参数缺失或格式错误
  • 请求体解析失败
  • 业务校验失败

401 Unauthorized

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"

{
  "error": "Unauthorized",
  "message": "缺少有效的身份认证"
}

场景: 需要身份认证但未提供或认证失败

注意:

  • 401表示"未认证"
  • 必须包含WWW-Authenticate头部

403 Forbidden

HTTP/1.1 403 Forbidden

{
  "error": "Forbidden",
  "message": "没有权限访问该资源"
}

场景: 服务器理解请求,但拒绝执行

401 vs 403:

401:你是谁?(未认证)
403:我知道你是谁,但你不允许访问(无权限)

404 Not Found

HTTP/1.1 404 Not Found

{
  "error": "Not Found",
  "message": "请求的资源不存在"
}

场景: 请求的资源不存在

使用:

  • URL路径错误
  • 资源已被删除
  • 资源ID不存在

405 Method Not Allowed

HTTP/1.1 405 Method Not Allowed
Allow: GET, POST, HEAD

{
  "error": "Method Not Allowed",
  "message": "不支持DELETE方法"
}

场景: 请求方法不被允许

注意:

  • 必须返回Allow头部

409 Conflict

HTTP/1.1 409 Conflict

{
  "error": "Conflict",
  "message": "资源状态冲突",
  "details": "该用户名已被占用"
}

场景: 请求与服务器当前状态冲突

使用:

  • 重复创建已存在资源
  • 版本冲突(乐观锁)
  • 并发修改冲突

410 Gone

HTTP/1.1 410 Gone

{
  "error": "Gone",
  "message": "该资源已永久删除"
}

场景: 资源曾经存在,但已永久删除

与404的区别:

  • 404:资源不存在(可能是URL错误)
  • 410:资源曾经存在,现在已删除

422 Unprocessable Entity

HTTP/1.1 422 Unprocessable Entity

{
  "error": "Unprocessable Entity",
  "message": "语义错误",
  "details": "库存不足,无法创建订单"
}

场景: 请求格式正确,但语义错误(如业务规则验证失败)

400 vs 422:

400:语法错误(JSON格式错误、参数类型错误)
422:语义错误(JSON格式正确,但业务校验失败)

429 Too Many Requests

HTTP/1.1 429 Too Many Requests
Retry-After: 3600
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640995200

{
  "error": "Too Many Requests",
  "message": "请求过于频繁,请稍后再试"
}

场景: 请求过于频繁,被限流

5xx 服务器错误状态码

表示服务器处理请求时发生错误。

500 Internal Server Error

HTTP/1.1 500 Internal Server Error

{
  "error": "Internal Server Error",
  "message": "服务器内部错误",
  "request_id": "abc123"
}

场景: 服务器内部错误,无法完成请求

使用:

  • 未捕获的异常
  • 代码逻辑错误
  • 不应向用户暴露详细错误信息

502 Bad Gateway

HTTP/1.1 502 Bad Gateway

{
  "error": "Bad Gateway",
  "message": "网关或代理收到无效响应"
}

场景: 网关或代理从上游服务器收到无效响应

常见原因:

  • 后端服务未启动
  • 后端服务崩溃
  • 网络不通

503 Service Unavailable

HTTP/1.1 503 Service Unavailable
Retry-After: 60

{
  "error": "Service Unavailable",
  "message": "服务暂时不可用"
}

场景: 服务器暂时无法处理请求(过载或维护)

使用:

  • 服务维护中
  • 服务器过载
  • 熔断器打开

504 Gateway Timeout

HTTP/1.1 504 Gateway Timeout

{
  "error": "Gateway Timeout",
  "message": "网关超时"
}

场景: 网关或代理在等待上游服务器响应时超时

502 vs 504:

502:收到无效响应(连接成功,但响应错误)
504:未收到响应(连接成功,但等待超时)

深入理解

状态码选择决策树

请求处理结果
    |
    ├─ 成功?
    │   ├─ 创建资源?
    │   │   ├─ 是 → 201 Created
    │   │   └─ 否 → 继续判断
    │   │
    │   ├─ 无返回内容?
    │   │   ├─ 是 → 204 No Content
    │   │   └─ 否 → 继续判断
    │   │
    │   ├─ 部分数据?
    │   │   ├─ 是 → 206 Partial Content
    │   │   └─ 否 → 200 OK
    │   │
    │   └─ 异步处理?
    │       ├─ 是 → 202 Accepted
    │       └─ 否 → 200 OK
    │
    ├─ 重定向?
    │   ├─ 永久移动?
    │   │   ├─ 保持方法?
    │   │   │   ├─ 是 → 308 Permanent Redirect
    │   │   │   └─ 否 → 301 Moved Permanently
    │   │   └─ 临时移动?
    │   │       ├─ 保持方法?
    │   │       │   ├─ 是 → 307 Temporary Redirect
    │   │       │   └─ 否 → 302 Found
    │   │       └─ 缓存验证?
    │   │           └─ 是 → 304 Not Modified
    │
    ├─ 客户端错误?
    │   ├─ 参数错误?
    │   │   ├─ 语法错误?
    │   │   │   ├─ 是 → 400 Bad Request
    │   │   │   └─ 否 → 422 Unprocessable Entity
    │   │   └─ 未认证?
    │   │       ├─ 是 → 401 Unauthorized
    │   │       └─ 无权限?
    │   │           ├─ 是 → 403 Forbidden
    │   │           └─ 不存在?
    │   │               ├─ 是 → 404 Not Found
    │   │               └─ 方法不允许?
    │   │                   ├─ 是 → 405 Method Not Allowed
    │   │                   └─ 冲突?
    │   │                       ├─ 是 → 409 Conflict
    │   │                       └─ 限流?
    │   │                           └─ 是 → 429 Too Many Requests
    │
    └─ 服务器错误?
        ├─ 内部错误?
        │   ├─ 是 → 500 Internal Server Error
        │   └─ 网关错误?
        │       ├─ 无效响应?
        │       │   ├─ 是 → 502 Bad Gateway
        │       │   └─ 超时?
        │       │       ├─ 是 → 504 Gateway Timeout
        │       │       └─ 服务不可用?
        │       │           └─ 是 → 503 Service Unavailable

RESTful API状态码规范

成功响应:
GET    /users       → 200 OK + 用户列表
GET    /users/123   → 200 OK + 用户详情
POST   /users       → 201 Created + 新用户 + Location头
PUT    /users/123   → 200 OK + 更新后用户 / 204 No Content
PATCH  /users/123   → 200 OK + 更新后用户 / 204 No Content
DELETE /users/123   → 204 No Content

错误响应:
400 Bad Request     → 参数验证失败
401 Unauthorized    → 未登录
403 Forbidden       → 无权限
404 Not Found       → 资源不存在
409 Conflict        → 资源冲突
422 Unprocessable   → 业务规则验证失败
429 Too Many Requests → 请求过于频繁
500 Internal Server Error → 服务器内部错误

状态码与SEO

SEO友好的状态码:

200 OK           正常索引
301 Redirect     传递权重到新URL
302 Redirect     不传递权重(临时跳转)
404 Not Found    正常处理,不索引
410 Gone         告诉搜索引擎删除索引
500 Error        影响网站评分

最佳实践

API错误响应格式

{
  "error": {
    "code": "INVALID_PARAMETER",
    "message": "请求参数错误",
    "status": 400,
    "details": [
      {
        "field": "email",
        "message": "邮箱格式不正确"
      },
      {
        "field": "age",
        "message": "年龄必须在18-100之间"
      }
    ],
    "path": "/api/users",
    "timestamp": "2024-01-01T00:00:00Z",
    "request_id": "req_abc123"
  }
}

状态码使用规范

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/api/users', methods=['POST'])
def create_user():
    data = request.get_json()

    # 参数校验 → 400
    if not data or 'email' not in data:
        return jsonify({
            'error': 'Bad Request',
            'message': '缺少必需参数:email'
        }), 400

    # 业务校验 → 422
    if not validate_email(data['email']):
        return jsonify({
            'error': 'Unprocessable Entity',
            'message': '邮箱格式不正确'
        }), 422

    # 冲突检查 → 409
    if User.query.filter_by(email=data['email']).first():
        return jsonify({
            'error': 'Conflict',
            'message': '该邮箱已被注册'
        }), 409

    # 创建成功 → 201
    user = User.create(data)
    return jsonify({
        'id': user.id,
        'email': user.email,
        'created_at': user.created_at
    }), 201, {'Location': f'/api/users/{user.id}'}

@app.route('/api/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
    user = User.query.get(user_id)

    # 资源不存在 → 404
    if not user:
        return jsonify({
            'error': 'Not Found',
            'message': f'用户 {user_id} 不存在'
        }), 404

    # 成功 → 200
    return jsonify({
        'id': user.id,
        'email': user.email
    }), 200

@app.errorhandler(500)
def internal_error(error):
    # 服务器错误 → 500
    return jsonify({
        'error': 'Internal Server Error',
        'message': '服务器内部错误',
        'request_id': g.request_id
    }), 500

Nginx状态码配置

# 自定义错误页面
error_page 400 /errors/400.html;
error_page 401 /errors/401.html;
error_page 403 /errors/403.html;
error_page 404 /errors/404.html;
error_page 500 502 503 504 /errors/50x.html;

# 精确匹配错误页面
location = /errors/400.html {
    internal;
}

# 限流返回429
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
location /api/ {
    limit_req zone=api burst=20 nodelay;
    limit_req_status 429;
    proxy_pass http://backend;
}

面试要点

  1. 状态码分类:1xx信息、2xx成功、3xx重定向、4xx客户端错误、5xx服务器错误
  2. 常用状态码:200、201、204、301、302、304、400、401、403、404、500、502、503
  3. 401 vs 403:401未认证,403无权限
  4. 400 vs 422:400语法错误,422语义错误
  5. 301 vs 302:301永久重定向,302临时重定向

常见面试追问:

  • 401和403有什么区别?
  • 301和302有什么区别?
  • 什么时候用201,什么时候用200?
  • 400和422有什么区别?
  • 502和504有什么区别?
  • 如何设计API错误响应?