symfony路由requirements必须显式声明,未声明则默认仅排除斜杠,存在安全隐患;正则需用单引号包裹、手动添加^$锚定,且不自动继承或全局生效。

requirements 必须显式声明,不写等于放行所有字符串
没加 requirements 的 {id} 参数,默认只排除斜杠(/),其他如 ..%2fetc%2fshadow、abc、0123 全部能过。这不是“宽松”,是安全隐患。
- YAML 中必须用单引号包裹正则:
requirements: { id: '\d+' },双引号会让\d被 YAML 解析器吃掉 - PHP 注解里直接写:
requirements={"id": "\d+"},不用额外转义 -
\d+会匹配0123,但业务上往往要“无前导零的正整数”,得写成^[1-9]\d*$或^([1-9]\d*|0)$ - 正则必须自己加
^和$锚定,Symfony 不自动补——"\d+"和"^\d+$"效果完全不同
多个参数要分别约束,不能靠“继承”或“全局配置”
Symfony 没有全局 requirements,requirements 只作用于当前路由或当前路由集合。想复用规则,得手动复制、用 YAML 锚点,或封装工具函数。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- YAML 中用锚点复用:
&id_constraint '\d+',再用*id_constraint引用 - PHP 构建路由时,
RouteCollection没有setRequirements(),必须对每个Route单独调用setRequirement('id', '\d+') - 别漏掉其他参数:写了
{id}的约束,但忘了{slug}或{year},就等于留了个后门 - 同名 requirement 会被覆盖,不是合并——
$route->setRequirement('id', '\d+')->setRequirement('id', '[1-9]\d*')最终只生效后者
可选参数 + requirements 怎么共存
defaults 让参数可省略,requirements 仍对其实际值生效——两者不冲突,但路径写法和控制器参数默认值必须配套。
- 路径里写
/{q?},控制器方法就得写public function search(string $q = '') -
defaults={"q": ""}+requirements={"q": ".{2,50}"}:空字符串合法,非空时必须 2–50 字符 -
defaults={"page": 1}+requirements={"page": "\d+"}:/search 和 /search/1 都匹配,/search/abc 直接 404 - 别在路径里写
{_controller}——这是 Symfony 内部保留名,写了会导致路由匹配失败
用负向先行断言排除特定值,比如避开 /login 被动态路由捕获
当泛型路由(如 /{slug})可能误匹配 /login、/api 等固定路径时,正则的 (?!...) 是唯一干净解法。
- 排除含
abc的所有值:requirements={"url": "^((?!abc).)*$"} - 精确排除
login或register:requirements={"slug": "^(?!login$|register$).+$"} - 注意:这种正则性能略低,别在高并发入口路由滥用;优先考虑调整路由顺序(把
/login放在/{slug}前面) - 测试时别只测
/login,还要试/login/extra——^$锚定的是整个参数值,不是路径前缀
^ 和 $ 必须手写,requirements 不做任何隐式包装;还有,defaults 和 requirements 是两套独立逻辑,缺一不可,光设默认值不加约束,等于没设。










