hyperf 不支持语法级路由组多层嵌套,仅支持前缀拼接式“嵌套”;推荐使用 addgroup 链式拼接(如 /api + /v1)、单文件分版本管理或注解 prefix 定义多级前缀。

Hyperf 官方不支持路由组的多层嵌套(比如 addGroup('/v1', fn() => addGroup('/user', fn() => ...))),这是关键前提。所谓“嵌套”,实际是前缀叠加,靠手动拼接或单层分组实现,不是语法级嵌套。
你真正需要的是:如何让 /api/v1/users、/api/v1/posts、/api/v2/users 这类带多级前缀的路由清晰组织。下面直接说清楚怎么做:
路由组前缀拼接(最常用且推荐)
Hyperf 的 addGroup() 只接受一个字符串前缀 + 一个闭包,闭包内再调用 addGroup() 是合法的,但效果只是路径拼接,不是嵌套作用域。例如:
Router::addGroup('/api', function () {
Router::addGroup('/v1', function () {
Router::get('/users', 'App\Controller\UserController@list');
Router::post('/users', 'App\Controller\UserController@create');
});
Router::addGroup('/v2', function () {
Router::get('/users', 'App\Controller\UserController@listV2');
});
});
访问地址分别是:
GET /api/v1/users-
POST /api/v1/users GET /api/v2/users
✅ 这就是你实际能用的“嵌套”写法,本质是两层 addGroup 串联,路径自动拼接,无需额外处理。
单文件集中管理多前缀路由
把不同版本或模块的路由拆到独立文件,再统一引入(适合中大型项目):
在 config/routes.php 中:
// 加载 v1 路由 require BASE_PATH . '/routes/v1.php'; // 加载 v2 路由 require BASE_PATH . '/routes/v2.php'; // 加载 admin 路由 require BASE_PATH . '/routes/admin.php';
然后创建 routes/v1.php:
<?php use Hyperf\HttpServer\Router\Router;
Router::addGroup('/api/v1', function () {
Router::get('/users', 'App\Controller\V1\UserController@list');
Router::get('/posts', 'App\Controller\V1\PostController@index');
});这样逻辑更清晰,也便于团队分工和版本隔离。
注解路由实现多级前缀(更简洁)
如果你用 @AutoController 或 @Controller,可以直接在类上定义完整前缀:
<?php namespace App\Controller\V1;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
#[Controller(prefix: '/api/v1')]
class UserController
{
#[GetMapping('/users')]
public function list()
{
return ['version' => 'v1', 'data' => []];
}
}访问:GET /api/v1/users
✅ 不依赖 addGroup,语义更直观,适合新项目或模块化开发。
注意事项
-
addGroup的前缀必须以/开头,但不能以/结尾(如'/api/'会导致匹配失败); - 路由参数如
{id}支持正则约束,例如{id:\d+},放在路径里即可; - 中间件可绑定到整个组:
Router::addGroup('/api/v1', ['middleware' => [AuthMiddleware::class]], function () { ... });
不需要找“嵌套教程”,Hyperf 就没这个概念。按前缀拼接或注解前缀组织,就足够覆盖所有常见场景。











