最稳妥的api版本控制方案是用带前缀的模块(如apiv1)承载各版本,配合显式urlrule路由映射和物理隔离的控制器;避免模块id与url前缀同名导致路由冲突,禁用user组件session,严格校验参数并统一异常抛出。

Yii 框架本身不内置 API 版本控制机制,直接靠路由参数或请求头做版本分流容易失控。最稳妥、可维护性最强的做法是:用模块(Module)承载每个 API 版本,配合显式路由前缀和隔离的命名空间。
为什么不能把 v1 当模块 ID 直接用?
模块 ID 和 URL 路由前缀语义重叠时,Yii 会优先匹配模块而非路由规则,导致请求进错地方。比如你配置了 'v1' => ['class' => 'api\modules\v1\Module'],又在 urlManager.rules 里写了 'v1/<controller:>' => '<controller>/</controller>'</controller:>,请求 /v1/user 时框架可能直接去加载 v1 模块下的控制器,跳过你写的路由映射。
- 模块 ID 改成
apiV1、apiV2这类带前缀的非纯数字名,避免和路径前缀冲突 - URL 路由规则中仍保留
'v1/<controller:>'</controller:>作为静态前缀,但必须显式绑定到对应模块的控制器,例如:'v1/<controller:>' => 'api-v1/<controller>/</controller>'</controller:> - 同时设
'enableStrictParsing' => false,否则没匹配上的请求会直接 404,调试阶段尤其容易卡住
UrlRule 怎么配才不和模块抢路由?
别依赖 Yii 自动推导——它默认会把 /v1/user 解析成模块 v1 + 控制器 user,而不是你期望的“v1 版本的 user 接口”。必须用 yii\rest\UrlRule 显式声明 pattern 和 route 的映射关系。
- Yii 2 推荐写法:
['class' => 'yii\rest\UrlRule', 'pattern' => 'v1/<controller:>', 'route' => 'api-v1/<controller>']</controller></controller:> - Yii 3 更清晰:
['pattern' => 'v2/<controller:>', 'route' => 'api-v2/<controller>']</controller></controller:>,把版本号从模块 ID 彻底剥离 - 所有
UrlRule配置必须放在urlManager.rules数组最前面,避免被泛匹配规则吞掉 - 如果用了复数形式(如
users),记得设'pluralize' => false,否则/v1/user可能被重写成/v1/users
控制器怎么隔离 v1 和 v2 的逻辑?
共用一个 UserController 类,靠条件判断区分版本,后期根本没法测试、上线灰度、单独回滚。必须物理隔离控制器文件和命名空间。
- Yii 2:每个模块下放独立的
controllers/UserController.php,命名空间分别为api\modules\apiV1\controllers和api\modules\apiV2\controllers - Yii 3:推荐用目录结构隔离,如
src/Api/V1/Controllers/UserController,并在config/routes.php中显式绑定'v1/user' => \App\Api\V1\Controllers\UserController::class - 两个版本的控制器不要继承同一个基类(除非基类只含纯工具方法),尤其避免在基类里加字段校验或响应格式逻辑
- 若需共享模型行为,定义接口如
ApiUserContract,让 v1/v2 各自实现,而不是直接use app\models\User
BaseRestController 里哪些设置最容易翻车?
REST 接口无状态,但很多人误关了 user 组件或硬塞 session,结果 token 验证失败、CLI 调用报错、OAuth 流程中断。
- 必须设
Yii::$app->user->enableSession = false和Yii::$app->user->enableAutoLogin = false,但绝不能 unsetYii::$app->user或赋值为 null - 权限校验该用
authenticator行为就用,不该用的接口(如登录)就继承yii\rest\Controller,别在 behaviors 里临时 disable authenticator - 参数校验别堆在 action 里写
$request->get('id') !== null,统一用ActionFilter,并开启$strict = true,缺参数直接 400 - 错误抛出用
throw new BadRequestHttpException(...),别 return 数组或 echo 字符串,否则破坏全局响应格式
版本边界一旦划开,数据库迁移、配置文件、单元测试都得按版本拆开;共用表结构可以,但字段增删、索引调整必须同步评估对老版本的影响——这点最容易被忽略。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











