根本原因是 prefix 未被路由系统识别——Hyperf 仅在注解解析阶段记录 prefix,不自动注入 FastRoute 注册逻辑;需确保使用命名参数语法、正确扫描路径、避免与 @AutoController 冲突,并通过 php bin/hyperf.php route:list 验证实际注册结果。

为什么 @Controller(prefix: "/api") 不生效?
根本原因是 prefix 没被路由系统识别——Hyperf 不会自动把 prefix 注入到 FastRoute 的注册逻辑里,它只在注解解析阶段记录字段,后续是否使用、如何拼接,取决于你用的是哪种控制器声明方式。
常见错误现象:访问 /api/users 返回 404,但直接写 @GetMapping(path: "/users") 却能通;或者 prefix 写成 prefix="/api/v1"(带等号)导致 PHP 解析失败,注解直接被忽略。
-
@Controller必须和@GetMapping等 HTTP 方法注解在同一类中,且该类必须被扫描到(检查config/autoload/annotations.php中的scan.paths是否包含你的控制器目录) - prefix 值不支持表达式或变量,只能是纯字符串,如
"/api"或"/v2",不能写"/api/{version:\w+}" - Hyperf 3.0 要求 prefix 字段必须用命名参数语法:
#[Controller(prefix: "/api")],旧写法@Controller("prefix=/api")已失效 - 如果同时用了
@AutoController,它默认不读取 prefix,只按文件路径生成路由,此时@Controller(prefix: ...)完全被忽略
路由前缀拼接规则到底是怎么算的?
Hyperf 把 @Controller(prefix: "/api") 和 @GetMapping(path: "/users/{id:\d+}") 拼起来时,并不是简单字符串连接。它会先规范化路径:去掉 prefix 末尾的斜杠、path 开头的斜杠,再合并。
也就是说:prefix: "/api/" + path: "/users/123" → 实际注册为 /api/users/123;而 prefix: "/api" + path: "users/{id:\d+}" → 同样是 /api/users/{id:\d+}。中间多一个或少一个 / 都不影响结果。
当代理已经知道网站路由或内容URL,并且在启动前需要有效的sitemap XML、sitemap索引或robots.txt引用时,请使用sitemap。这是一个发布构件技能,而不是爬虫或SEO平台。
- path 为空字符串(
@GetMapping(path: ""))时,最终路由就是 prefix 本身,比如/api - path 以
/开头,会被自动截掉,所以写"/users"和"users"效果一样 - prefix 为空或 null,整个前缀被跳过,只注册 path 部分
- FastRoute 最终编译出的正则类似
^/api/users/(\d+)$,匹配时区分大小写,且不自动处理 trailing slash
多个 prefix 层级嵌套时谁优先?
Hyperf 不支持“嵌套 prefix”,比如父类写了 @Controller(prefix: "/admin"),子类再写 @Controller(prefix: "/user") —— 子类的 prefix 会完全覆盖父类,不会叠加。所谓“层级”只存在于手动组织的目录结构里,框架本身不感知继承关系。
真正起作用的只有当前类上最靠近的 @Controller 注解。如果你看到路由注册了 /admin/user/list,那大概率是 path 写成了 "/user/list",而不是靠两个 prefix 叠加出来的。
- 别依赖类继承传递 prefix,Hyperf 的注解扫描是扁平化的,每个类单独解析
- 想复用前缀逻辑,用常量或配置项定义,然后显式写进每个
@Controller(prefix: ...) - 如果用了模块化结构(如
App\Modules\User\Controller),prefix 应该由模块边界决定,而不是靠目录深度推导 - 注意:@AutoController 会根据命名空间和类名自动生成 prefix,与 @Controller 的 prefix 冲突时,前者优先级更低,会被后者覆盖
调试路由是否注册成功最有效的方法
别猜,直接看 FastRoute 编译后的路由表。Hyperf 启动后,所有注解路由都已固化进内存,运行时无法动态修改,所以问题一定出在启动阶段。
最快验证方式:启动服务后执行 php bin/hyperf.php route:list(Hyperf ≥ 3.0.5)。它会输出所有已注册的路由,包括 method、uri、handler,一眼就能看出 /api/users/{id:\d+} 是否存在、是否绑定到正确控制器方法。
- 如果列表里没有你的路由,说明注解根本没被扫描到——回去查
scan.paths和di:init-proxy是否执行 - 如果 uri 显示为
/users/{id:\d+}(缺 prefix),说明@Controller注解没生效或被跳过 - 如果 handler 显示为
NULL或匿名函数,说明控制器类没被正确加载,可能是 PSR-4 映射错误或文件名不匹配 - 注意:route:list 不显示未启用的中间件,也不校验正则是否合法,它只反映 FastRoute 当前持有的路由数据
../、不展开符号链接、不归一化重复斜杠。哪怕你写 prefix: "/api//v1//",最终注册的也是 /api//v1//users —— FastRoute 会原样接受,但浏览器或 curl 默认不发双斜杠,导致匹配失败。这种细节不会报错,只会静默 404。


















