正确路由写法是使用原生PCRE正则,如product/([0-9]+)?而非(:num)?;([a-zA-Z0-9_]+)比\d+更稳妥;([^/]+)比(:any)更灵活可控;需在控制器中对空参数判空并手动类型转换。

必须用 PCRE 正则,不能依赖 (:num) 或 (:any) 的“可选”写法——它们根本不支持 ? 量词。
正则路由必须写成 ([0-9]+) 这类原生 PCRE 形式
CI3 的 (:num) 是语法糖,底层展开为 ([0-9]+),但它本身不识别 (:num)? 这种写法——? 会被当作文本字面量,导致路由完全不匹配。你写的 $route['product/(:num)?'] = 'products/detail/$1'; 实际等价于匹配字面路径 product/(:num)?,不是你想要的“ID 可有可无”。
正确写法是直接上 PCRE:
-
$route['product/([0-9]+)?'] = 'products/detail/$1';→ ID 可选,$1为空字符串时需在控制器里判空 -
$route['user/([a-zA-Z0-9_]+)/posts/([0-9]+)'] = 'user/posts/$1/$2';→ 区分大小写,且强制两段参数 - 避免写
(\d+):CI3 某些版本对\d支持不稳定,显式用[0-9]更稳妥
([^/]+) 和 (:any) 看似等价,但行为完全不同
(:any) 是 CI 封装的占位符,只匹配一个不含 / 的路径段;而正则里的 ([^/]+) 是明确的“非斜杠字符至少一个”,语义清晰、可控性强。更重要的是:(:any) 无法嵌套或加量词,([^/]+) 可以自由组合。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
例如想匹配 /section/a/b/c/d/e 并只取前两段:
- ❌ 错误:
$route['section/(:any)/(:any)']—— 只能匹配恰好两段,/section/a/b/c就 404 - ✅ 正确:
$route['section/([^/]+)/([^/]+)/?.*'] = 'sections/view/$1/$2';——.*吃掉后续所有内容,$1和$2始终稳定 - 注意顺序:这条规则必须放在
$route['section/about']这类具体路由之后,否则会提前截断
带可选参数的多级路径容易踩的坑
常见需求是支持 /a、/a/b、/a/b/c 全部落到同一个方法,但只传前 N 段。这时候不能靠堆砌 (:any),而要用正则锚定开头 + 忽略后面:
-
$route['([a-zA-Z0-9]+)/?'] = 'pages/view/$1';→ 匹配单段,末尾/可选 -
$route['([a-zA-Z0-9]+)/([a-zA-Z0-9]+)/?.*'] = 'pages/view/$1/$2';→ 匹配两段,第三段起全部忽略 -
$1和$2在控制器中收到的是字符串,不是自动转整型,id类参数仍需手动(int)转换 - 如果 URL 含中文或特殊符号,
[a-zA-Z0-9]不够用,改用([^/]+)更通用
真正麻烦的不是写正则,而是忘记控制器里对空参做兜底——比如 $route['product/([0-9]+)?'] 传来的 $1 是空字符串,不是 null,empty($id) 要比 !$id 更安全。还有就是 404 页面崩掉,往往是因为视图里用了 base_url() 却没在 404 控制器里 $this->load->helper('url');。


















