注解路由需满足扫描、声明、注册三步:启用config/autoload/annotations.php中'scan'=>true并配置控制器路径;控制器类添加@controller或@autocontroller;方法使用@getmapping等注解绑定路径与方法。

@Controller 和 @GetMapping 等注解不是“写上去就生效”的,必须满足扫描、声明、注册三步条件,缺一不可。否则路由根本不会进全局表,route:list 里也看不到。
确认注解扫描已启用且路径正确
Hyperf 不默认扫描注解,靠 config/autoload/annotations.php 中的 'scan' => true 触发。常见失效原因就是这个配置没开,或控制器路径没加进 'paths':
- 检查
config/autoload/annotations.php是否存在且含'scan' => true -
'paths'必须显式包含控制器目录,例如app/Controller;若用app/Http/Controllers,就得写全路径 - 路径末尾不加斜杠,也不加通配符(
app/Controller/**无效) - 修改后需清空
runtime/container和runtime/cache目录,否则旧缓存会掩盖问题
控制器类必须带 @Controller 或 @AutoController
仅方法上写 #[GetMapping] 没用——Hyperf 要先识别出“这是一个控制器类”,才会去扫描它的方法。两类注解用途不同:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
-
#[Controller(prefix: '/api')]:适合需要统一前缀、多方法共用中间件的场景;类内所有方法路由自动拼接该前缀 -
#[AutoController(prefix: 'user')]:更轻量,自动把 public 方法名转为小写 + 下划线风格路径(如getUserInfo→/user/get_user_info),但只支持 GET/POST - 二者都要求类在
app/Controller(或你配置的扫描路径)下,且命名空间与目录结构一致
方法注解要匹配 HTTP 方法和参数提取方式
注解本身只是声明,真正取参靠类型提示或参数注解,这里容易混淆:
-
#[GetMapping('/users/{id}')]中的{id}是路径参数,必须用#[Param('id')]或类型提示int $id才能注入;仅写$request->path()拿不到 -
#[PostMapping('/login')]默认不解析 JSON Body,需显式加#[Body]注解或手动调$request->getBody()->getContents() - 查询参数(
?page=1&size=10)用#[Query]或$request->query(),不能混用#[Param] - PHP 8 Attributes 写法是
#[GetMapping(path: '/users')],不是旧式/** @GetMapping() */;后者在新版本中已被弱化支持,IDE 补全差、反射慢
验证是否注册成功最直接的方式
别靠 curl 猜,先看路由表是否收录:
- 执行
php bin/hyperf.php route:list,检查输出里有没有你的路径和方法 - 若没出现,90% 是扫描路径错、注解没生效、或类没被加载(比如命名空间写成
App\Controllers但扫描的是App\Controller) - 若出现但 404,检查请求 method 是否匹配(
#[GetMapping]不响应 POST)、路径是否带前缀(@Controller('/v1')后实际是/v1/users) - 中间件未生效?注解里的
middleware:参数只对当前路由生效,@Controller上设的中间件不会自动继承到方法级,得重复写或改用路由组
Hyperf 的注解路由本质是启动时生成一张静态映射表,不是运行时动态解析。所以任何改动——从注解写法、路径配置,到依赖注入的构造函数签名——都必须重启服务或清缓存才能反映。这点和 Laravel 的运行时反射完全不同,容易误判为“代码没生效”。










