T-DOC
  • Laravel-11
  • Laravel-10
  • Laravel-6X
  • Laravel-5.5
Dcat-Admin
  • Yii2
  • 重构2
  • Laravel-11
  • Laravel-10
  • Laravel-6X
  • Laravel-5.5
Dcat-Admin
  • Yii2
  • 重构2
  • 前言

    • 关于 Yii
    • 从 Yii 1.1 升级
    • Yii 2.0 升级说明
    • 贡献者指引
    • 捐献和赞助
  • 版本管理

    • 发行说明
    • 版本说明
    • 更新记录
  • 快速入门

    • 安装 Yii
    • 目录结构
    • 部署
    • Hello world
    • 使用表单
    • 使用数据库
    • 使用 Gii 生成代码
    • 编辑器与 IDE
  • 核心架构

    • 请求生命周期
    • 单一入口
    • 应用主体
    • 组件
    • 属性
    • 事件
    • 行为
    • 配置
    • 别名
    • 类自动加载
    • 服务定位器
    • 依赖注入容器
  • 高级应用模板

    • 安装
    • 框架结构
    • 运行测试
    • 环境与配置
    • 自定义应用模板
  • 基础功能

    • 路由
    • 控制器
    • 过滤器
    • 请求
    • 响应
    • 模型
    • 视图
    • 模块
    • 小部件
    • 前端资源
    • 扩展
    • Sessions 和 Cookies
    • 错误处理
    • 日志
  • 数据库

    • 数据库访问对象(DAO)
    • 查询构造器
    • 活动记录
    • 数据库迁移
    • Redis
    • Sphinx
    • Elasticsearch
    • MongoDB
  • 安全

    • 认证
    • 授权
    • 加密
    • Email 认证
    • 验证码
    • 社会化登录
    • 密码
  • 进阶功能

    • 缓存
    • 发送邮件
    • HTTP 客户端
    • 国际化
    • 队列
    • 控制台应用
    • 助手类
    • 验证器
  • RESTful Web 服务

    • 快速入门
    • 资源
    • 控制器
    • 路由
    • 格式化响应
    • 认证
    • 速率限制(限流)
    • 版本化
    • 错误处理
  • 开发工具

    • 调试工具栏和调试器
    • 使用 Gii 生成代码

版本化

一个优秀的 API 应该是支持 版本化的,即更改和新特性在新版本的 API 中实现,而不是不断地在同一个版本上修改。

与 Web 应用程序不同,您可以完全控制客户端和服务器端代码,API 意味着由超出您控制范围的客户端使用。出于这个原因,应该尽可能维护 API 的向后兼容性(BC)。如果有必要进行可能破坏 BC 的更改,则应该在 API 的新版本中引入它,并提高版本号。现有的客户端可以继续使用旧的、可用的 API 版本,新的或升级的客户端可以获得新 API 版本中的新功能。

小贴士:有关设计 API 版本号的更多信息,请参阅 语义化版本。

常用方法

实现 API 版本控制的一种常见方法是将版本号嵌入到 API 的 URL 中。例如:http://example.com/v1/users 表示 API 版本 1 的 /users 端点(endpoint)。

API 版本控制的另一种方法是将版本号放在 HTTP 请求头中,这种方法最近得到了发展。这通常是通过 Accept 头文件完成的,例如:

// 通过一个参数
Accept: application/json; version=v1
// 通过供应商内容类型
Accept: application/vnd.company.myapp-v1+json

这两种方法都有各自的优点和缺点,对于每种方法都有很多争论。下面您将看到一种实用的 API 版本控制策略,它混合了这两种方法:

  • 将 API 实现的每个主要版本放在一个单独的模块中,其 ID 为主要版本号(例如:v1、v2等) ,自然地,API 的 URL 中将包含主要的版本号。
  • 在每个主版本中(以及相应的模块中),使用 Accept HTTP 请求头来确定次要版本号,并相应地编写条件代码来响应次要版本。

版本化模块

对于服务于主版本的每个模块来说,它应该包含服务于该特定版本的资源和控制器类。为了更好地分离代码责任,您可以保留一组通用的基础资源和控制器类,并在每个单独的版本模块中对它们进行子类化。在子类中,实现具体的代码,如覆盖 Model::fields()。

创建版本化模块

我们可以通过 Gii 的 module 构造器来实现基本的目录结构,记得取消控制器和视图创建,具体如图:

Gii 创建版本化模块

或者通过命令行:

php yii gii/module --moduleID=v1 --moduleClass='api\modules\v1\V1Module'

然后自行删除创建的 DefaultController 和 views 目录。然后在应用配置中,这样写:

......
    'modules' => [
        'v1' => [
            'class' => 'api\modules\v1\V1Module',
        ],
    ],

创建控制器

然后查看 api\modules\v1 目录下,如果没有一个 controllers 目录,那就新建一个,用来放控制器。你可以使用命令行来创建一个 rest 控制器,示例如下:

php yii gii/controller --controllerClass='api\modules\v1\controllers\UserController' --baseClass='yii\rest\ActiveController' --cations=

你也可以用 gii 来创建控制器,示例如下:

Gii 创建 rest 控制器

创建表

如果你还没有创建 user 表,没有关系,我们的 Yii 的高级应用模板,自带了示例的 user 表的迁移文件,你可以执行控制台命令,快速创建 user 表,具体如下:

php yii migrate/up

如图所示,这样就创建了 user 表:

数据库迁移创建表

创建模型

有了 user 表之后,我们在 api\modules\v1\models 目录下存放模型,当然你也可以放在其他或者公共的目录,你可以使用命令行来创建一个模型,示例如下:

php yii gii/model --tableName='demo_user' --ns='api\modules\v1\models' --modelClass='User' --generateLabelsFromComments=1 --useTablePrefix=1

你也可以用 gii 来创建模型,示例如下:

Gii 创建 rest 模型

然后在之前创建的 api\modules\v1\controllers\UserController 中,增加一句,示例如下:

namespace api\modules\v1\controllers;

class UserController extends \yii\rest\ActiveController
{
    public $modelClass = 'api\modules\v1\models\User';
}

目录结构

经过控制器和模型的创建,您的项目目录,示例如下:

api/
    common/
        controllers/
            UserController.php
            PostController.php
        models/
            User.php
            Post.php
    modules/
        v1/
            controllers/
                UserController.php
                PostController.php
            models/
                User.php
                Post.php
            V1Module.php
        v2/
            controllers/
                UserController.php
                PostController.php
            models/
                User.php
                Post.php
            V2Module.php

应用程序配置

您的应用程序配置如下所示:

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 的用户。

不同主要版本的代码可以很好地隔离,都归功于 Yii 的 模块(modules)。但是,模块仍然可以通过公共基类及其他共享资源,实现跨模块代码重用。

次要版本号

要处理次要版本号,可以利用内容协商特性,它由 yii\filters\ContentNegotiator 内容协商行为来提供。当决定支持哪种内容类型时,该行为会设置 yii\web\Response::acceptParams 属性。

例如,如果一个请求被发送带有 HTTP 报头 Accept: application/json; version=v1,经过内容协商后,yii\web\Response::acceptParams 将包含值 ['version' => 'v1']。

根据 acceptParams 中的版本信息,你可以在动作、资源类、序列化器等地方编写条件代码,以此来提供适当的功能。

由于次要版本的定义要求维护向后兼容性,所以,希望在代码中不会有太多的版本验证。否则,您可能需要创建一个新的主版本。

💖喜欢本文档的,欢迎点赞、收藏、留言或转发,谢谢支持!
作者邮箱:zhuzixian520@126.com,github地址:github.com/zhuzixian520

Last Updated:
Contributors: Hans
Prev
速率限制(限流)
Next
错误处理