首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何实现 RESTful API 接口服务版本化?

如何实现 RESTful API 接口服务版本化?

作者头像
Tinywan
发布2025-09-11 19:19:23
发布2025-09-11 19:19:23
5900
代码可运行
举报
文章被收录于专栏:开源技术小栈开源技术小栈
运行总次数:0
代码可运行

概述

一个好的 API 设计应该是 “版本化” 的:变更和新的功能应该在 API 新版本中实现,而不是在一个版本上持续更改。与Web应用程序不同,您可以完全控制客户端和服务器端 代码,API 是为了给超出控制的客户端使用。

因此,应该尽可能的保持向后兼容性,如果有一些变化不能向后兼容,你应该在新版本的 API 中采用它同时增加版本号。

现有客户端可以继续使用旧版本的 API,新的或升级的客户端可以在新的 API 版本中获得新的功能。

如何实现

关于如何实现 API 版本,一个常见的做法是在 API 的 URL 中嵌入版本号。例如:http://example.com/v1/users代表/users版本 1 的 API。

另一种 API 版本化的方法, 最近用的非常多的是把版本号放入 HTTP 请求头,通常是通过Accept头,如下:

代码语言:javascript
代码运行次数:0
运行
复制
// 通过参数
Accept: application/json; version=v1
// 通过vendor的内容类型
Accept: application/vnd.company.myapp-v1+json

这两种方法都有优点和缺点, 而且关于他们也有很多争论。 下面我们描述在一种 API 版本混合了这两种方法的一个实用的策略:

  • 把每个主要版本的 API 实现在一个单独的模块 ID 的主版本号 (例如v1v2)。 自然,API 的 url 将包含主要的版本号。
  • 在每一个主要版本 (在相应的模块),使用AcceptHTTP 请求头 确定小版本号编写条件代码来响应相应的次要版本。

为每个模块提供一个主要版本, 它应该包括资源类和控制器类为特定服务版本。

更好的分离代码, 你可以保存一组通用的基础资源和控制器类, 并用在每个子类版本模块。 在子类中, 实现具体的代码例如Model::fields()

你的代码可以类似于如下的方法组织起来

代码语言:javascript
代码运行次数:0
运行
复制
api/
├──common/                  # 公共基础层(跨版本复用资源)
│   ├──controllers/         # 基础控制器(抽象类/通用方法)
│   │   ├──BaseUserController.php# 用户相关基础控制逻辑
│   │   └──BasePostController.php# 内容相关基础控制逻辑
│   ├──models/              # 基础数据模型(共享属性/方法)
│   │   ├──BaseUser.php     # 用户模型基类(含通用字段验证)
│   │   └──BasePost.php     # 内容模型基类(含通用数据处理)
│   └──services/            # 公共服务层(跨版本业务逻辑)
│       ├──UserService.php# 用户相关通用服务(如权限校验)
│       └──PostService.php# 内容相关通用服务(如格式转换)
│
├──modules/                 # 版本模块层(按API版本隔离)
│   ├──v1/                  # v1版本API(独立部署/迭代)
│   │   ├──controllers/     # 版本专属控制器(继承基础控制器)
│   │   │   ├──UserController.php# v1用户接口实现
│   │   │   └──PostController.php# v1内容接口实现
│   │   ├──models/          # 版本专属模型(继承基础模型)
│   │   │   ├──User.php     # v1用户模型(扩展字段/逻辑)
│   │   │   └──Post.php     # v1内容模型(扩展字段/逻辑)
│   │   ├──services/        # 版本专属服务(业务逻辑隔离)
│   │   │   ├──UserService.php# v1用户业务实现
│   │   │   └──PostService.php# v1内容业务实现
│   │   └──Module.php       # v1版本模块配置(路由/依赖)
│   │
│   └──v2/                  # v2版本API(结构同v1,独立迭代)
│       ├──controllers/
│       │   ├──UserController.php
│       │   └──PostController.php
│       ├──models/
│       │   ├──User.php
│       │   └──Post.php
│       ├──services/
│       │   ├──UserService.php
│       │   └──PostService.php
│       └──Module.php
│
└──routes/                  # 路由配置层(统一入口管理)
    ├──v1.php               # v1版本路由定义
    └──v2.php               # v2版本路由定义

你的应用程序配置应该这样

代码语言:javascript
代码运行次数:0
运行
复制
return [
    'modules' => [
        'v1' => [
            'class' => 'app\modules\v1\Module',
        ],
        'v2' => [
           'class' => 'app\modules\v2\Module',
        ],
    ],
    'components' => [
        'urlManager' => [
            'enablePrettyUrl' => true,
            'enableStrictParsing' => true,
            'showScriptName' => false,
            'rules' => [
                ['class' => 'yii\rest\UrlRule', 'controller' => ['v1/user', 'v1/post']],
                ['class' => 'yii\rest\UrlRule', 'controller' => ['v2/user', 'v2/post']],
            ],
        ],
    ],
];

因此,http://example.com/v1/users将返回 版本1 的用户列表, 而http://example.com/v2/users将返回 版本2 的用户。

使用模块,将不同版本的代码隔离。通过共用基类和其他类跨模块重用代码也是有可能的。

版本控制优点

  1. 职责分层:新增services层剥离业务逻辑,使控制器专注于请求响应处理,模型专注于数据交互,符合 "单一职责原则"。
  2. 继承复用:通过BaseXXX基类实现跨版本代码复用,版本专属类仅扩展差异逻辑,减少重复代码。
  3. 版本隔离:每个版本模块包含完整的 "控制器 - 模型 - 服务" 闭环,便于独立迭代和维护(如 v2 需重构时不影响 v1)。
  4. 路由集中:将路由配置从模块中抽出单独管理,便于 API 入口统一管控和文档生成。
  5. 扩展性:新增服务层和路由层后,后续可轻松接入中间件、权限控制等功能,无需修改核心业务代码。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-08-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源技术小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 如何实现
  • 版本控制优点
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档