Hyperf出现404问题,首要检查static_handler_locations是否配置为["/"]导致所有请求被当作静态文件处理而绕过路由层;其次验证注解是否被正确扫描(scan.paths配置及di:init-proxy执行),并用route:list命令确认路由是否真实注册。

检查 static_handler_locations 是否劫持了所有路由
Hyperf 默认启用 Swoole 的静态文件处理器,一旦在 config/autoload/server.php 中配置了 static_handler_locations 且包含 /,所有请求(包括 API)都会被当成静态资源处理,直接返回 404。这不是路由没注册,而是根本没进路由层。
常见错误配置:
-
"static_handler_locations" => ["/"]—— 全路径拦截,最危险 -
"static_handler_locations" => ["/public", "/static"]—— 看似合理,但若项目未严格分离静态资源目录,仍可能误匹配
解决方式:注释或删除 static_handler_locations 行,重启服务。如确需静态处理,应限定为明确的子路径(如 /assets),并确保该路径下真实存在对应文件。
确认注解是否被扫描到(scan.paths 和 di:init-proxy)
Hyperf 3.0+ 使用 PHP 8 Attributes 注解(如 #[GetMapping]),但注解不会自动生效——必须被框架扫描、解析、缓存后才参与路由注册。漏扫 = 路由不存在 = 404。
关键检查点:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
-
config/autoload/annotations.php中的scan.paths必须显式包含控制器所在目录,例如:BASE_PATH . '/app/Controller',不能只写'app/Controller' - 修改
scan.paths或新增控制器后,必须手动执行:php bin/hyperf.php di:init-proxy - 若启用
SCAN_CACHEABLE=true,但runtime/container/annotation/下无有效缓存文件,注解将静默失效 - Docker 部署时,
runtime/container/不能被.dockerignore过滤,也不能在启动脚本里清空
验证路由规则是否匹配请求方法与路径结构
Hyperf 的路由匹配是精确的:方法(GET/POST)、路径字符串、参数正则约束三者必须同时满足。任一不匹配,就 404,且不报错。
典型陷阱:
-
#[PostMapping("/user")]不响应 GET /user —— 返回 405,不是 404;但用户常误以为是“找不到” -
#[GetMapping("/user/{id:\d+}")]对/user/abc直接返回 404,不进控制器;这是设计行为,不是 bug - 路径末尾斜杠敏感:
/api/v1/users和/api/v1/users/是两条不同路由,不能混用 - 大小写敏感:Linux 环境下
/User≠/user,控制器类名、方法名、路由 path 都需统一小写(推荐惯例)
用 php bin/hyperf.php route:list 实时核对已注册路由
这个命令会输出当前加载的所有路由(含 HTTP 方法、路径、控制器、中间件),是判断“路由是否真的存在”的唯一可信依据。如果某条路由没出现在列表里,说明它根本没被注册——问题一定出在注解扫描、配置加载或语法错误上。
执行前注意:
- 确保
di:init-proxy已运行,否则列表为空或不全 - 检查命令输出中是否有 Warning 或 ParseError,比如注解语法错误(如漏写括号、引号不闭合)会导致整文件跳过
- 若使用模块化结构(如多应用或多包),确认
scan.paths涵盖所有模块的控制器路径
真正棘手的 404 往往不是“路由写错了”,而是“路由压根没注册进来”。别猜,先跑一遍 route:list —— 它不撒谎,也不隐藏细节。


















