路由顺序必须从具体到模糊:ci4按定义顺序逐条匹配,命中即止;动态路由须置于静态路由之后,避免(:any)吞噬所有路径,优先使用(:num)或正则提升安全性,并及时清理路由缓存。

路由顺序必须从具体到模糊
CI4 按定义顺序逐条匹配,一旦命中就停止。把 $routes->get('(:any)') 放在最前面,所有静态路由(比如 /admin、/api/v1/users)全被吃掉,根本不会执行。
- ✅ 正确做法:先写明确路径,再写通配符
- ❌ 错误示例:
$routes->get('(:any)', 'Page::show/$1');写在$routes->get('/contact', 'Page::contact')前面 - ⚠️ 注意
(:any)不匹配/(空路径),若需覆盖根路径,单独写$routes->get('/', 'Home::index')
用 resource() 替代手写 CRUD 路由
手动写 $routes->get('/posts')、$routes->get('/posts/create')、$routes->post('/posts')……不仅重复,还容易漏掉 PUT/DELETE 或命名不一致。
- ✅ 一行替代全部:
$routes->resource('posts')自动生成 7 条标准 REST 路由(index、show、new、create、edit、update、delete) - ⚠️ 控制器名必须是复数名词(
Posts),方法名严格按约定(如index()、show($id)) - ? 可局部禁用:
$routes->resource('posts', ['except' => ['create', 'delete']])
动态参数优先用 (:num) 而不是 (:any)
(:any) 匹配任意非斜杠字符,但会把本该 404 的非法输入(如 /user/abc)也交给控制器处理,徒增 DB 查询和逻辑判断负担。
- ✅ 数字 ID 场景用
(:num):$routes->get('/user/(:num)', 'User::show/$1')—— 非数字直接跳过匹配,不进控制器 - ✅ 英文 slug 场景用正则:
$routes->get('([a-z0-9\-]+)', 'Blog::show/$1'),比(:any)更安全精准 - ⚠️
(:any)实际等价于([^/]+),不校验内容,仅防路径截断
路由缓存不清理,改了也不生效
CI4 默认缓存路由配置到 app/Cache/RouteCollection.php,改完 Routes.php 不清缓存,旧规则还在跑。
- ✅ 必做两步:
php spark cache:clear清全局缓存,再php spark routes看实际生效列表 - ⚠️ 开发时可临时关缓存:在
app/Config/Cache.php中设$handlers = [],但别在生产环境这么干 - ? 修改路由后仍 404?第一反应不是代码错,而是先跑
spark routes确认那条规则真在列表里










