Skip to content

RESTful API 全面详解

什么是 RESTful API?

RESTful API 是一种基于 REST(Representational State Transfer,表述性状态转移)架构风格设计的 API。它不是标准或协议,而是一种设计风格,用于创建可扩展、可靠且易于维护的 Web 服务。

RESTful API 设计规范

1. 资源命名规范

使用名词而非动词

http

apl
# 正确 - 使用名词
GET /users
GET /users/123
POST /users

# 错误 - 使用动词
GET /getUsers
POST /createUser
使用复数形式

http

# 推荐使用复数
GET /users
GET /users/123/orders

# 单数形式(不推荐)
GET /user
GET /user/123/order
资源层次结构

http

# 表示层次关系
GET /users/123/orders          # 用户123的所有订单
GET /users/123/orders/456      # 用户123的订单456
过滤、排序、分页

http

# 使用查询参数
GET /users?role=admin&active=true      # 过滤
GET /users?sort=name,-age              # 排序(name升序,age降序)
GET /users?page=2&limit=20             # 分页
GET /users?fields=id,name,email        # 字段选择

2. HTTP 方法使用规范

HTTP 方法描述幂等性安全性
GET获取资源
POST创建资源
PUT更新或创建资源
PATCH部分更新资源
DELETE删除资源
具体使用示例

http

js
# 获取资源
GET /users/123

# 创建资源
POST /users
Content-Type: application/json
{
  "name": "John Doe",
  "email": "john@example.com"
}

# 完整更新资源
PUT /users/123
Content-Type: application/json
{
  "name": "John Smith",
  "email": "john.smith@example.com"
}

# 部分更新资源
PATCH /users/123
Content-Type: application/json
{
  "email": "new.email@example.com"
}

# 删除资源
DELETE /users/123

Content-Type(内容类型)与 Accept(接受类型)

特性Content-TypeAccept
方向主要描述请求体格式描述期望的响应格式
请求中声明客户端发送数据的格式声明客户端希望接收数据的格式
响应中声明服务器返回数据的格式一般不用于响应
必需性有请求体时通常必需可选,但有最佳实践价值

实际开发中的应用

1. 正确的 API 调用示例

javascript

js
// 前端代码调用 API
async function updateUser(userId, userData) {
  const response = await fetch(`/api/users/${userId}`, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json', // 我发送的是 JSON
      'Accept': 'application/json'        // 我希望接收 JSON
    },
    body: JSON.stringify(userData)
  });
  
  return response.json();
}

3. HTTP 状态码使用

2xx 成功
  • 200 OK:请求成功
  • 201 Created:资源创建成功
  • 202 Accepted:请求已接受处理,但尚未完成
  • 204 No Content:请求成功,但无返回内容
3xx 重定向
  • 301 Moved Permanently:资源已永久移动
  • 302 Found:资源临时移动
  • 304 Not Modified:资源未修改(缓存相关)
4xx 客户端错误
  • 400 Bad Request:请求格式错误
  • 401 Unauthorized:需要身份验证
  • 403 Forbidden:无权限访问
  • 404 Not Found:资源不存在
  • 405 Method Not Allowed:HTTP方法不允许
  • 409 Conflict:资源状态冲突
  • 429 Too Many Requests:请求过于频繁
5xx 服务器错误
  • 500 Internal Server Error:服务器内部错误
  • 501 Not Implemented:功能未实现
  • 503 Service Unavailable:服务不可用

返回JSON格式数据

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器解析和生成。

示例响应体结构:

json
jsonCopy Code{
  "status": "success",
  "code": 200,
  "message": "操作成功",
  "data": {
    "id": 1,
    "name": "示例数据"
  }
}
  • status‌:表示请求的状态(如 success, error)。
  • code‌:HTTP状态码或自定义错误码。
  • message‌:状态消息,用于描述操作的结果或错误原因。
  • data‌:实际返回的数据。

错误处理和标准化错误信息

当出现错误时,应返回清晰的错误信息,帮助开发者快速定位问题。

示例错误响应体:

json
jsonCopy Code{
  "status": "error",
  "code": 404,
  "message": "资源未找到",
  "details": "指定的资源ID不存在"
}
  • details‌:提供更详细的错误信息,有助于调试。

实际开发中的重要考虑

1. 认证和授权

认证与授权在实际开发中的实现细节,尤其是JWT(JSON Web Token)认证和OAuth 2.0授权。

JWT(JSON Web Token)认证

JWT是一种无状态的令牌认证机制,常用于Web API和微服务。

  • 令牌本身就是用户身份和权限的信息,服务端不用存session,直接验证令牌即可。
  • 令牌内容是一个经过签名的JSON字符串,通常包括用户ID、角色、过期时间等。

2. 认证流程

步骤一:用户登录,获取JWT令牌

HTTP

http
POST /auth/login
Content-Type: application/json

{
  "username": "user@example.com",
  "password": "password123"
}
  • 客户端提交用户名和密码,服务端验证是否正确。
步骤二:服务端返回JWT令牌

JSON

json
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
  • 令牌内容由三部分组成:Header(头)、Payload(载荷)、Signature(签名)。
  • 服务端用密钥对令牌进行签名。
步骤三:客户端保存令牌(通常存localStorage或Cookie)
步骤四:客户端访问受保护接口时,带上令牌

HTTP

GET /users/me
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
  • 在请求头加Authorization: Bearer <token>,服务端验证令牌即可。

3. 服务端如何验证JWT?

  • 解析令牌,验证签名是否正确(确保没被伪造)。
  • 检查令牌是否过期。
  • 从令牌中读取用户信息和权限,决定是否允许访问。

4. JWT的优缺点

优点:

  • 无状态,服务端不用保存session,扩展性强。
  • 可扩展到微服务、分布式架构。
  • 可以直接存放权限、角色等信息,API可以快速做权限判断。

缺点:

  • 一旦令牌泄露,别人可以伪造身份。
  • 令牌不能主动失效(只能等到过期或用黑名单)。
  • 刷新机制要自己实现。

5. 实际开发要点

  • 令牌要设置合理的过期时间,比如15分钟~2小时。
  • 不要把敏感信息(如密码)放在JWT里。
  • 密钥要妥善保管,否则令牌验证就失效了。
  • HTTPS必须开启,防止令牌被窃听。
  • 注意跨域和CSRF问题,存储方式要选对。

http

js
POST /auth/login
Content-Type: application/json
{
  "username": "user@example.com",
  "password": "password123"
}

# 响应
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

http

http
GET /users/me
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...