2、资源与URI设计:资源的概念、URI的命名规范(使用名词、小写、连字符)、避免动词、版本控制策略(URL路径 vs Header)

2.1 资源(Resource)的核心概念

在RESTful架构中,资源是API操作的核心对象。资源可以是一个实体(如用户、订单)、一个集合(如用户列表)、或者一个过程(如计算、转换)。每个资源必须有一个唯一的标识符,即URI(Uniform Resource Identifier)。

资源设计的关键原则:

  • 抽象性:资源是业务概念的抽象,而非数据库表的直接映射。
  • 唯一性:每个资源通过URI全局唯一标识。
  • 可寻址性:客户端通过URI即可定位并操作资源。
  • 无状态性:服务器不保存客户端状态,每次请求包含所有必要信息。
💡 设计提示: 资源应围绕业务名词(如 users、orders、products)建模,而非围绕操作(如 getUser、createOrder)。资源是名词,操作由HTTP方法表达。

2.2 URI命名规范

URI是资源的地址,其命名直接影响API的可读性、一致性和可维护性。以下是业界公认的规范:

规范 说明 正确示例 错误示例
使用名词(复数) 资源是名词,URI路径应使用名词复数形式 /users /getUser
全小写 避免大小写敏感导致的歧义 /order-items /OrderItems
连字符(-)分隔 提高可读性,优于下划线或驼峰 /user-profiles /user_profiles 或 /userProfiles
避免动词 操作由HTTP方法(GET/POST/PUT/DELETE)表达 GET /users/123 GET /getUserById/123
层级关系用斜杠 表示资源之间的从属关系 /users/123/orders /users/123-orders
避免文件扩展名 内容类型由 Content-Type Header决定 /users/123 /users/123.json
📋 命名规范速查表:
  • ✅ /users — 用户集合
  • ✅ /users/42 — 单个用户
  • ✅ /users/42/orders — 用户的订单集合
  • ✅ /order-items — 订单项集合(连字符)
  • ❌ /getUserOrders — 包含动词
  • ❌ /User_Profile — 大小写混合+下划线

2.3 避免动词:让HTTP方法说话

RESTful API的核心原则之一是利用HTTP标准方法表达操作语义,而非在URI中嵌入动词。这样设计的好处:

  • 统一接口:所有资源使用相同的HTTP方法集合,降低学习成本。
  • 可缓存性:GET、PUT、DELETE等方法的语义明确,便于代理和缓存服务器处理。
  • 幂等性:PUT、DELETE是幂等的,POST不是,URI设计不应破坏这些语义。
HTTP方法 操作语义 URI示例 错误动词式URI
GET 获取资源(读取) GET /users/42 GET /getUser/42
POST 创建资源(非幂等) POST /users POST /createUser
PUT 全量替换资源(幂等) PUT /users/42 PUT /updateUser/42
PATCH 部分更新资源 PATCH /users/42 PATCH /modifyUser/42
DELETE 删除资源 DELETE /users/42 DELETE /removeUser/42
⚠️ 常见反模式: 有些API使用 /api/v1/users/getUserInfo 或 /api/v1/deleteOrder,这完全违背了RESTful原则。正确的做法是:GET /users/42 和 DELETE /orders/99。动词应永远留在HTTP方法中,而非URI路径里。

2.4 版本控制策略:URL路径 vs Header

API版本控制是保证向后兼容性的关键手段。业界主要有两种策略:URL路径版本控制 和 Header版本控制。以下是详细对比:

维度 URL路径版本控制 Header版本控制
实现方式 在URI路径中嵌入版本号,如 /v1/users 通过自定义Header(如 Accept: application/vnd.myapi.v2+json)
可读性 ⭐️⭐️⭐️⭐️⭐️ 直观,浏览器/工具直接可见 ⭐️⭐️⭐️ 隐藏,需查看请求头
路由复杂度 低,框架原生支持路径匹配 高,需解析Header并分发到不同处理器
缓存友好性 ⭐️⭐️⭐️⭐️ 不同版本URL不同,缓存自动隔离 ⭐️⭐️ 同一URL不同Header,缓存需额外配置
默认版本 需显式指定,无版本则返回最新或报错 可设置默认版本,未指定时使用最新
URL整洁性 ⭐️⭐️⭐️ 路径多一段 /v1/ ⭐️⭐️⭐️⭐️⭐️ URL保持简洁
推荐场景 公开API、移动端、第三方集成 内部微服务、需要优雅降级的场景
🏆 推荐实践: 对于大多数Go Web业务接口,URL路径版本控制 是更稳妥的选择。它简单、直观、易于调试,且与Go的HTTP路由库(如 gorilla/mux、chi、gin)天然兼容。示例:/v1/users、/v2/users。

2.5 资源与URI设计总览图

下图展示了资源、URI命名规范、HTTP方法与版本控制之间的整体关系:

资源与URI设计总览 资源 (Resource) URI命名规范 HTTP方法(避免动词) 版本控制策略 命名规范细则 • 使用名词复数:/users • 全小写:/order-items • 连字符分隔:/user-profiles • 层级用斜杠:/users/42/orders HTTP方法映射 • GET → 读取资源 • POST → 创建资源 • PUT → 全量替换 • DELETE → 删除资源 版本控制策略 • URL路径:/v1/users • Header:Accept: vnd.myapi.v2 • 推荐:URL路径(公开API) • 推荐:Header(内部服务) 核心原则:名词URI + HTTP方法语义 + 显式版本控制

2.6 Go代码示例:版本化资源路由

以下是用Go的 gin 框架实现URL路径版本控制的示例:

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    // v1 版本的用户接口
    v1 := r.Group("/v1")
    {
        v1.GET("/users", listUsersV1)
        v1.GET("/users/:id", getUserV1)
        v1.POST("/users", createUserV1)
        v1.PUT("/users/:id", updateUserV1)
        v1.DELETE("/users/:id", deleteUserV1)
    }

    // v2 版本的用户接口(可能返回更多字段)
    v2 := r.Group("/v2")
    {
        v2.GET("/users", listUsersV2)
        v2.GET("/users/:id", getUserV2)
        v2.POST("/users", createUserV2)
        v2.PUT("/users/:id", updateUserV2)
        v2.DELETE("/users/:id", deleteUserV2)
    }

    r.Run(":8080")
}

func listUsersV1(c *gin.Context) {
    c.JSON(200, gin.H{"version": "v1", "users": []string{"alice", "bob"}})
}

func listUsersV2(c *gin.Context) {
    c.JSON(200, gin.H{"version": "v2", "users": []string{"alice", "bob", "charlie"}})
}
// 其他处理器实现略...
💡 版本控制最佳实践:
  • 版本号使用整数(v1、v2),避免语义化版本(如 v1.2.3)。
  • 每个版本独立路由组,便于维护和废弃旧版本。
  • 废弃版本时,在响应Header中添加 Deprecation: true 和 Sunset: Sat, 31 Dec 2025 23:59:59 GMT 通知客户端。
  • 不要在同一版本内同时支持URL路径和Header两种方式,保持一致性。

2.7 资源层级与URI设计示例

以下表格展示了常见业务场景下的资源层级与URI设计:

业务场景 资源层级 URI示例 说明
获取用户列表 集合 GET /v1/users 返回所有用户
获取单个用户 单体 GET /v1/users/42 路径参数标识用户ID
获取用户的订单 子集合 GET /v1/users/42/orders 层级关系:用户 → 订单
获取订单中的商品 子集合 GET /v1/users/42/orders/99/items 多级层级
搜索用户 集合+查询参数 GET /v1/users?q=alice&page=1 查询参数用于过滤/分页
获取商品分类 集合 GET /v1/product-categories 连字符分隔多单词
获取分类下的商品 子集合 GET /v1/product-categories/5/products 层级关系
📌 关键总结:
  1. 资源 = 名词,URI路径只包含名词,不包含动词。
  2. 命名规范:全小写、连字符分隔、复数形式、层级用斜杠。
  3. 操作语义:完全由HTTP方法(GET/POST/PUT/PATCH/DELETE)表达。
  4. 版本控制:推荐URL路径方式(/v1/),简单直观,适合大多数Go Web项目。
  5. 一致性:整个API遵循同一套命名和版本策略,降低客户端集成成本。