codeigniter 3 路由是线性扫描,顺序即优先级:固定路径最前,带占位符的中等粒度规则次之,通配符兜底规则最后;(:any) 放太前会导致参数错乱或 404;正则路由可精准控制字符范围与大小写;404_override 不参与匹配,仅作最终 fallback。

路由匹配是线性扫描,不是智能推导
CodeIgniter 3 的路由引擎不会“分析所有规则再选最优”,它从 $route 数组开头逐行比对,一旦某条规则的 URI 模式匹配当前请求路径,就立即执行对应控制器,并停止后续所有检查。这意味着:顺序即优先级,没有回溯、没有权重、没有嵌套分组。
常见错误现象是访问 /blog/2024/08 却进了 pages/view 而不是预期的 news/archive——根本原因就是泛化规则写在了前面,把本该命中固定路径的机会截断了。
- 固定路径(如
admin/login、api/v1/status)必须放在最前 - 带占位符的中等粒度规则(如
product/(:num)、user/(:any))紧随其后 - 通配符兜底规则(如
(:any)/(:any)/(:any)/.*、(:any))必须放在最后
为什么 (:any) 放太前会导致全站 404 或参数错乱
(:any) 等价于 ([^/]+),只匹配单段非斜杠字符串,但它本身不关心段数。如果你把 $route['(:any)'] = 'pages/view/$1' 写在第一条,那么 /products/123 会被当作一个整体匹配到 $1 = 'products/123'(因为 CI 默认未启用严格模式),结果传给 pages/view 的参数是非法字符串,控制器里 $this->uri->segment(2) 可能为空,base_url() 在 404 视图里也可能因辅助函数未加载而报错。
真正安全的兜底写法是显式限定段数+捕获剩余:
$route['(:any)/(:any)/(:any)/.*'] = 'pages/view/$1/$2/$3'; $route['(:any)/(:any)'] = 'pages/view/$1/$2'; $route['(:any)'] = 'pages/view/$1';
注意这三条的顺序不能颠倒,否则 /a/b/c/d/e 会先被第二条吃掉(=a, =b),第三段及以后丢失。
当代理已经知道网站路由或内容URL,并且在启动前需要有效的sitemap XML、sitemap索引或robots.txt引用时,请使用sitemap。这是一个发布构件技能,而不是爬虫或SEO平台。
正则路由怎么写才能精准控制大小写和字符范围
CI3 允许直接使用 PCRE 正则替代 (:any) 等占位符,这是绕过默认模糊匹配的关键手段。比如要强制区分大小写、禁止下划线、只接受字母数字组合:
- 用
$route['([A-Za-z0-9]+)/([A-Za-z0-9]+)'] = 'content/show/$1/$2'替代(:any)/(:any) - 若需支持中文路径,得用 Unicode 字符类:
$route['([\x{4e00}-\x{9fa5}a-zA-Z0-9]+)/([\x{4e00}-\x{9fa5}a-zA-Z0-9]+)'] = 'article/detail/$1/$2'(需 PHP 启用u修饰符,CI3 默认支持) - 避免滥用
.*开头的正则——它会吞掉整个 URL,包括域名部分,CI3 不会做路径截取预处理
404_override 不是路由规则,别指望它救火
$route['404_override'] = 'errors/not_found' 是路由引擎彻底失败后的 fallback,它不参与任何匹配流程。如果某条本该生效的规则因顺序靠后而没被扫到,请求根本不会进这个分支,而是直接由 CI 底层抛出原始 404 错误——此时你自定义的视图甚至不会加载,更别说调用 base_url() 了。
真正需要关注的是 routes.php 文件里的声明顺序。调试时建议:
- 每条规则上方加注释说明覆盖范围,例如
// 匹配 /api/v1/users/123 - 临时把疑似冲突的规则移到文件最顶端单独测试
- 用
var_dump($this->uri->segments())在目标控制器里确认实际收到的参数是否符合预期
复杂路径逻辑(比如多级分类、动态模块前缀)不要强塞进路由层,容易失控;优先在控制器里做 segment() 判断和跳转,比维护一长串正则更可持续。










