URI 路由
什么是 URI 路由?
URI 路由将 URI 与控制器的方法关联起来。
CodeIgniter 有两种路由方式。一种是 定义式路由,另一种是 自动路由。通过定义式路由,你可以手动定义路由规则,这种方式允许更灵活的 URL 结构。自动路由则基于约定自动映射 HTTP 请求到对应的控制器方法,无需手动定义路由。
首先我们来看定义式路由。如需使用自动路由,请参阅 自动路由(改进版)。
设置路由规则
路由规则定义在 app/Config/Routes.php 文件中。在该文件中,你会看到创建了一个 RouteCollection 类的实例($routes
),用于指定自定义路由条件。可以使用占位符或正则表达式来定义路由。
当定义路由时,需选择与 HTTP 方法(请求方法)对应的路由方法。例如处理 GET 请求时使用 get()
方法:
<?php
$routes->get('/', 'Home::index');
路由左侧指定 路由路径 (相对于 BaseURL 的 URI 路径,以 /
开头),右侧映射到 路由处理器 (控制器和方法 Home::index
),并可传递参数给控制器。
控制器和方法应按静态方法的形式列出,使用双冒号分隔类和方法,例如 Users::list
。
若方法需要参数,可在方法名后使用斜杠分隔:
<?php
// Calls $Users->list()
$routes->get('users', 'Users::list');
// Calls $Users->list(1, 23)
$routes->get('users/1/23', 'Users::list/1/23');
示例
以下是几个基础路由示例:
当 URL 第一段包含 journals 时,将映射到 \App\Controllers\Blogs
类,并调用 默认方法 (通常为 index()
):
<?php
$routes->get('journals', 'Blogs');
当 URL 包含 blog/joe 时,映射到 \App\Controllers\Blogs
类的 users()
方法,ID 参数设为 34
:
<?php
$routes->get('blog/joe', 'Blogs::users/34');
当 URL 第一段为 product,第二段为任意内容时,映射到 \App\Controllers\Catalog
类的 productLookup()
方法:
<?php
$routes->get('product/(:segment)', 'Catalog::productLookup');
当 URL 第一段为 product,第二段为数字时,映射到 \App\Controllers\Catalog
类的 productLookupByID()
方法,并将匹配值作为参数传递:
<?php
$routes->get('product/(:num)', 'Catalog::productLookupByID/$1');
HTTP 方法路由
可以使用任意标准 HTTP 方法(GET、POST、PUT、DELETE、OPTIONS 等):
<?php
$routes->post('products', 'Product::feature');
$routes->put('products/1', 'Product::feature');
$routes->delete('products/1', 'Product::feature');
通过 match()
方法传入方法数组,可匹配多个 HTTP 方法:
<?php
$routes->match(['GET', 'PUT'], 'products', 'Product::feature');
指定路由处理器
控制器的命名空间
当以字符串形式指定控制器和方法名时,若控制器名称未以 \
开头,系统会自动添加 默认命名空间:
<?php
// Routes to \App\Controllers\Api\Users::update()
$routes->post('api/users', 'Api\Users::update');
若以 \
开头,则视为完全限定类名:
<?php
// Routes to \Acme\Blog\Controllers\Home::list()
$routes->get('blog', '\Acme\Blog\Controllers\Home::list');
也可通过 namespace
选项指定命名空间:
<?php
// Routes to \Admin\Users::index()
$routes->get('admin/users', 'Users::index', ['namespace' => 'Admin']);
详见 分配命名空间。
数组可调用语法
在 4.2.0 版本加入.
从 v4.2.0 开始,可使用数组可调用语法指定控制器:
$routes->get('/', [\App\Controllers\Home::class, 'index']);
或使用 use
关键字:
use App\Controllers\Home;
$routes->get('/', [Home::class, 'index']);
若忘记添加 use App\Controllers\Home;
,控制器类名将被解析为 \Home
而非 App\Controllers\Home
。
备注
使用数组可调用语法时,类名始终视为完全限定类名,因此 默认命名空间 和 namespace 选项 将失效。
数组可调用语法与占位符
若存在占位符,参数将按指定顺序自动设置:
use App\Controllers\Product;
$routes->get('product/(:num)/(:num)', [Product::class, 'index']);
// The above code is the same as the following:
$routes->get('product/(:num)/(:num)', 'Product::index/$1/$2');
但在路由中使用正则表达式时,自动配置的参数可能不正确。此时可手动指定参数:
use App\Controllers\Product;
$routes->get('product/(:num)/(:num)', [[Product::class, 'index'], '$2/$1']);
// The above code is the same as the following:
$routes->get('product/(:num)/(:num)', 'Product::index/$2/$1');
使用闭包
可使用匿名函数(闭包)作为路由目标。当用户访问对应 URI 时,该函数将被执行,适用于快速执行小任务或显示简单视图:
<?php
use App\Libraries\RSSFeeder;
$routes->get('feed', static function () {
$rss = new RSSFeeder();
return $rss->feed('general');
});
指定路由路径
占位符
典型路由示例如下:
<?php
$routes->get('product/(:num)', 'Catalog::productLookup');
路由的第一个参数是待匹配的 URI,第二个参数是目标路由。当 URL 路径第一段为 “product” 且第二段为数字时,将使用 Catalog
类的 productLookup
方法。
占位符是代表正则表达式模式的字符串,在路由过程中会被替换为实际正则表达式,主要用于提升可读性。
可用占位符列表:
占位符 |
描述 |
---|---|
(:any) |
匹配从该位置到 URI 末尾的所有字符,可能包含多个段 |
(:segment) |
匹配除斜杠( |
(:num) |
匹配任意整数 |
(:alpha) |
匹配任意字母字符串 |
(:alphanum) |
匹配任意字母数字组合字符串 |
(:hash) |
与 |
备注
{locale}
不能作为占位符或路由其他部分,保留用于 本地化。
(:any) 的行为
注意单个 (:any)
会匹配 URL 中的多个段(如果存在)。
例如路由:
<?php
$routes->get('product/(:any)', 'Catalog::productLookup/$1');
将匹配 product/123、product/123/456、product/123/456/789 等。
默认情况下,上述示例中若 $1
占位符包含斜杠(/
),传递给 Catalog::productLookup()
时仍会分割为多个参数。
备注
自 v4.5.0 起,可通过配置选项修改此行为,详见 多 URI 段作为单一参数。
控制器实现应考虑最大参数数量:
<?php
namespace App\Controllers;
class Catalog extends BaseController
{
public function productLookup($seg1 = false, $seg2 = false, $seg3 = false)
{
echo $seg1; // Will be 123 in all examples
echo $seg2; // false in first, 456 in second and third example
echo $seg3; // false in first and second, 789 in third
}
}
或使用 可变数量的参数值列表:
<?php
namespace App\Controllers;
class Catalog extends BaseController
{
public function productLookup(...$params)
{
echo $params[0] ?? null; // Will be 123 in all examples
echo $params[1] ?? null; // null in first, 456 in second and third example
echo $params[2] ?? null; // null in first and second, 789 in third
}
}
重要
请勿在 (:any)
后放置其他占位符,因为传递给控制器方法的参数数量可能变化。
若不需要匹配多段,应在定义路由时使用 (:segment)
:
<?php
$routes->get('product/(:segment)', 'Catalog::productLookup/$1');
该路由仅匹配 product/123,其他情况返回 404 错误。
自定义占位符
可创建自定义占位符来完全定制路由体验。
使用 addPlaceholder()
方法添加新占位符,第一个参数是占位符字符串,第二个参数是替换的正则表达式。需在添加路由前调用:
<?php
$routes->addPlaceholder('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}');
$routes->get('users/(:uuid)', 'Users::show/$1');
正则表达式
可使用正则表达式定义路由规则。允许任何有效正则表达式及反向引用。
重要
注意:使用反向引用时需使用美元符号语法而非双反斜杠语法。典型正则路由示例:
<?php
$routes->get('products/([a-z]+)/(\d+)', 'Products::show/$1/id_$2');
上述示例中,类似 products/shirts/123 的 URI 将调用 Products
控制器的 show()
方法,原始第一、二段作为参数传递。
通过正则表达式可捕获包含斜杠的段(通常用于分隔多个段)。例如用户访问受密码保护区域后重定向回原页面:
<?php
$routes->get('login/(.+)', 'Auth::login/$1');
默认情况下,若 $1
占位符包含斜杠,传递给 Auth::login()
时仍会分割为多个参数。
备注
自 v4.5.0 起,可通过配置选项修改此行为,详见 多 URI 段作为单一参数。
关于正则表达式学习,推荐访问 regular-expressions.info。
备注
可混合使用占位符和正则表达式。
视图路由
在 4.3.0 版本加入.
若只需渲染无逻辑视图,可使用 view()
方法(始终视为 GET 请求)。第二个参数指定视图名称:
<?php
// Displays the view in /app/Views/pages/about.php
$routes->view('about', 'pages/about');
若路由中使用占位符,可通过 $segments
数组在视图中访问:
<?php
// Displays the view in /app/Views/map.php
$routes->view('map/(:segment)/(:segment)', 'map');
// Within the view, you can access the segments with
// $segments[0] and $segments[1] respectively.
重定向路由
网站改版常需页面重定向。使用 addRedirect()
方法指定旧路由重定向到新路由。第一个参数是旧路由 URI 模式,第二个参数是新 URI 或命名路由名称,第三个参数是 HTTP 状态码(默认 302 临时重定向):
<?php
$routes->get('users/profile', 'Users::profile', ['as' => 'profile']);
// Redirect to a named route
$routes->addRedirect('users/about', 'profile');
// Redirect to a URI
$routes->addRedirect('users/about', 'users/profile');
// Redirect with placeholder
$routes->get('post/(:num)/comment/(:num)', 'PostsComments::index', ['as' => 'post.comment']);
// Redirect to a URI
$routes->addRedirect('article/(:num)/(:num)', 'post/$1/comment/$2');
// Redirect to a named route
$routes->addRedirect('article/(:num)/(:num)', 'post.comment');
备注
自 v4.2.0 起,addRedirect()
支持占位符。
匹配重定向路由时,用户将在控制器加载前立即跳转。
环境限制
可创建仅特定环境可见的路由(如开发者本地工具)。使用 environment()
方法,参数为环境名称,闭包内定义的路由仅在该环境下可用:
<?php
$routes->environment('development', static function ($routes) {
$routes->get('builder', 'Tools\Builder::index');
});
任意 HTTP 方法路由
重要
此方法仅为向后兼容保留,新项目请勿使用。建议使用更合适的 HTTP 方法路由。
警告
使用 CSRF 保护 时,不会保护 GET 请求。若 add()
方法指定的 URI 可通过 GET 访问,CSRF 保护将失效。
使用 add()
方法定义支持任意 HTTP 方法的路由:
<?php
$routes->add('products', 'Product::feature');
备注
使用 HTTP 方法路由可提升性能,因为仅存储匹配当前请求方法的路由。
批量映射路由
重要
此方法仅为向后兼容保留,新项目请勿使用。建议使用更合适的方法。
警告
由于 map()
内部调用 add()
,同样不推荐使用。
使用 map()
方法批量定义路由数组:
<?php
$multipleRoutes = [
'product/(:num)' => 'Catalog::productLookupById',
'product/(:alphanum)' => 'Catalog::productLookupByName',
];
$routes->map($multipleRoutes);
仅命令行路由
备注
建议使用 Spark 命令处理 CLI 脚本,而非通过 CLI 调用控制器。详见 创建 Spark 命令。
通过 HTTP 方法创建的路由 CLI 不可访问,但 add()
创建的路由仍可在命令行使用。使用 cli()
方法创建仅 CLI 可用的路由:
<?php
$routes->cli('migrate', 'App\Database::migrate');
警告
若启用 自动路由(传统版) 并将命令文件置于 app/Controllers,他人可能通过自动路由(传统)HTTP 访问该命令。
全局选项
所有路由创建方法(get()
、post()
、resource() 等)均可接受选项数组作为最后一个参数,用于修改或限制生成的路由:
<?php
$routes->add('from', 'to', $options);
$routes->get('from', 'to', $options);
$routes->post('from', 'to', $options);
$routes->put('from', 'to', $options);
$routes->head('from', 'to', $options);
$routes->options('from', 'to', $options);
$routes->delete('from', 'to', $options);
$routes->patch('from', 'to', $options);
$routes->match(['GET', 'PUT'], 'from', 'to', $options);
$routes->resource('photos', $options);
$routes->map($array, $options);
$routes->group('name', $options, static function () {});
应用过滤器
可通过为路由添加过滤器来修改特定路由行为(如身份验证或 API 日志记录)。过滤器值可以是字符串或字符串数组:
匹配 app/Config/Filters.php 中定义的别名
过滤器类名
详见 控制器过滤器。
警告
若在 app/Config/Routes.php 设置路由过滤器(非 app/Config/Filters.php),建议禁用自动路由(传统)。启用 自动路由(传统版) 时,控制器可能通过不同 URL 访问,导致路由过滤器未生效。详见 仅使用定义路由。
别名过滤器
你可以为过滤器值指定一个 在 app/Config/Filters.php 中定义 的别名。
<?php
$routes->get('admin', ' AdminController::index', ['filter' => 'admin-auth']);
可为别名过滤器的 before()
和 after()
方法传递参数:
<?php
$routes->post('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']);
类名过滤器
在 4.1.5 版本加入.
直接指定过滤器类名:
<?php
$routes->get('admin', ' AdminController::index', ['filter' => \App\Filters\SomeFilter::class]);
多重过滤器
在 4.1.5 版本加入.
重要
自 v4.5.0 起始终启用 多重过滤器 ,v4.5.0 之前默认禁用,如需使用请参考 从 4.1.4 升级到 4.1.5。
指定过滤器数组:
<?php
$routes->get('admin', ' AdminController::index', ['filter' => ['admin-auth', \App\Filters\SomeFilter::class]]);
过滤器参数
可向过滤器传递额外参数:
<?php
$routes->add('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']);
此例中数组 ['dual', 'noreturn']
将作为 $arguments
传递给过滤器的 before()
和 after()
方法。
分配命名空间
虽然系统会自动添加 默认命名空间 到生成的控制器,但可通过 namespace
选项指定不同命名空间:
<?php
// Routes to \Admin\Users::index()
$routes->get('admin/users', 'Users::index', ['namespace' => 'Admin']);
新命名空间仅作用于单路由创建方法(如 get、post 等)。对于创建多路由的方法(如 group()
),新命名空间将附加到所有生成的路由。
限制主机名
通过“hostname”选项限制路由组仅在特定域名或子域生效:
<?php
$routes->get('from', 'to', ['hostname' => 'accounts.example.com']);
此示例仅允许 accounts.example.com 域名访问,主域 example.com 不可用。
多主机名限制
在 4.6.0 版本加入.
支持多个主机名限制:
<?php
$routes->get('from', 'to', ['hostname' => ['s1.example.com', 's2.example.com']]);
限制子域
通过 subdomain
选项限制路由仅在特定子域可用:
<?php
// Limit to media.example.com
$routes->get('from', 'to', ['subdomain' => 'media']);
设置值为星号(*
)可匹配任意子域,但无子域的 URL 不匹配:
<?php
// Limit to any sub-domain
$routes->get('from', 'to', ['subdomain' => '*']);
重要
此功能并非完美,生产环境前需充分测试。某些含点的域名可能导致误判。
偏移匹配参数
通过 offset
选项数值偏移匹配参数。适用于 API 版本号或语言字符串作为首段的情况:
<?php
$routes->get('users/(:num)', 'users/show/$1', ['offset' => 1]);
// Creates:
$routes['users/(:num)'] = 'users/show/$2';
反向路由
反向路由允许通过控制器、方法及参数定义链接,由路由器查找当前路由。这使得修改路由定义无需更新应用代码,常用于视图创建链接。
使用 url_to()
辅助函数获取路由。第一个参数是完全限定的控制器和方法(用双冒号分隔),后续参数传递路由参数:
<?php
// The route is defined as:
$routes->get('users/(:num)/gallery/(:num)', 'Galleries::showUserGallery/$1/$2');
?>
<!-- Generate the URI to link to user ID 15, gallery 12: -->
<a href="<?= url_to('Galleries::showUserGallery', 15, 12) ?>">View Gallery</a>
<!-- Result: 'http://example.com/users/15/gallery/12' -->
命名路由
你可以为路由命名以使你的应用更健壮。这为路由应用一个名称,之后可以被调用,即使路由定义发生变化,应用中所有使用 url_to()
构建的链接仍能正常工作,而无需你做任何修改。通过传递 as
选项并指定路由名称来为路由命名:
<?php
// The route is defined as:
$routes->get('users/(:num)/gallery/(:num)', 'Galleries::showUserGallery/$1/$2', ['as' => 'user_gallery']);
?>
<!-- Generate the URI to link to user ID 15, gallery 12: -->
<a href="<?= url_to('user_gallery', 15, 12) ?>">View Gallery</a>
<!-- Result: 'http://example.com/users/15/gallery/12' -->
这样做还有一个额外的好处,就是让视图更具可读性。
分组路由
你可以使用 group()
方法将路由分组到一个共用名称下。分组名称会成为出现在组内定义路由之前的一个路径段。这允许你减少构建大量共享相同开头字符串的路由所需的输入量,例如在构建管理区域时:
<?php
$routes->group('admin', static function ($routes) {
$routes->get('users', 'Admin\Users::index');
$routes->get('blog', 'Admin\Blog::index');
});
这将会为 users 和 blog URI 添加 admin 前缀,处理如 admin/users 和 admin/blog 的 URL。
设置命名空间
如果你需要为分组分配选项,例如 分配命名空间,请在回调函数之前进行设置:
<?php
$routes->group('api', ['namespace' => 'App\API\v1'], static function ($routes) {
$routes->resource('users');
});
这将处理指向 App\API\v1\Users
控制器的资源路由,对应的 URI 为 api/users。
设置过滤器
你也可以为一组路由使用特定的 过滤器。这将在控制器之前或之后始终运行该过滤器。这在身份验证或 API 日志记录场景中特别有用:
<?php
$routes->group('api', ['filter' => 'api-auth'], static function ($routes) {
$routes->resource('users');
});
过滤器的值必须与 app/Config/Filters.php 中定义的别名之一匹配。
备注
在 v4.5.4 之前的版本中,由于存在 bug,传递给 group()
的过滤器不会合并到传递给内部路由的过滤器中。
设置其他选项
有时可能需要为路由组应用过滤器或其他配置选项(如命名空间、子域等),而无需添加前缀。此时可将前缀设为空字符串:
<?php
$routes->group('', ['namespace' => 'Myth\Auth\Controllers'], static function ($routes) {
$routes->get('login', 'AuthController::login', ['as' => 'login']);
$routes->post('login', 'AuthController::attemptLogin');
$routes->get('logout', 'AuthController::logout');
});
嵌套分组
支持多层级分组以实现更精细的组织结构:
<?php
$routes->group('admin', ['filter' => 'myfilter1:config'], static function ($routes) {
$routes->get('/', 'Admin\Admin::index');
$routes->group('users', ['filter' => 'myfilter2:region'], static function ($routes) {
$routes->get('list', 'Admin\Users::list');
});
});
此例将处理 admin/users/list URL。外层 group()
的 filter
选项会与内层 group()
的选项合并。上述代码中,admin
路由运行 myfilter1:config
过滤器,admin/users/list
路由运行 myfilter1:config
和 myfilter2:region
过滤器。
备注
v4.6.0 之前,同一过滤器无法使用不同参数多次运行。
内层 group()
的选项会覆盖外层同名选项。
备注
v4.5.0 之前存在 bug,外层 group()
的选项不会与内层合并。
路由优先级
路由按定义顺序注册到路由表中。当访问 URI 时,将执行首个匹配的路由。
警告
若同一路由路径被多次定义且处理器不同,仅首个定义的路由生效。
可通过运行 spark routes 命令查看路由表。
调整路由优先级
处理模块路由时,若应用路由包含通配符可能导致模块路由无法正确处理。通过 priority
选项可降低路由处理优先级(数值越大优先级越低):
<?php
// First you need to enable processing of the routes queue by priority.
$routes->setPrioritize();
// Config\Routes
$routes->get('(.*)', 'Posts::index', ['priority' => 1]);
// Modules\Acme\Config\Routes
$routes->get('admin', 'Admin::index');
// The "admin" route will now be processed before the wildcard route.
要禁用此功能,传入 false
参数:
<?php
$routes->setPrioritize(false);
备注
默认所有路由优先级为 0,负值将转为绝对值。
路由配置选项
RouteCollection 类提供多个全局配置选项(位于 app/Config/Routing.php),可根据需求调整。
备注
app/Config/Routing.php 配置文件自 v4.4.0 起新增,旧版本需在 app/Config/Routes.php 使用 setter 方法修改设置。
默认命名空间
匹配控制器时,系统会将默认命名空间值添加到控制器名称前(默认 App\Controllers
)。设为空字符串(''
)则需每个路由指定完全限定命名空间:
<?php
// In app/Config/Routing.php
use CodeIgniter\Config\Routing as BaseRouting;
// ...
class Routing extends BaseRouting
{
// ...
public string $defaultNamespace = '';
// ...
}
// In app/Config/Routes.php
// Controller is \Users
$routes->get('users', 'Users::index');
// Controller is \Admin\Users
$routes->get('users', 'Admin\Users::index');
若控制器已命名空间化,可修改此值减少输入:
<?php
// This can be overridden in app/Config/Routes.php
$routes->setDefaultNamespace('App');
// Controller is \App\Users
$routes->get('users', 'Users::index');
// Controller is \App\Admin\Users
$routes->get('users', 'Admin\Users::index');
默认方法
当路由处理器仅指定控制器名时,使用此设置的方法(默认 index
):
// In app/Config/Routing.php
public string $defaultMethod = 'index';
如果你定义了以下路由:
$routes->get('/', 'Home');
当路由匹配时,将执行 App\Controllers\Home
控制器的 index()
方法。
备注
方法名称以 _
开头时不能用作默认方法。
但是,从 v4.5.0 开始,允许使用 __invoke
方法。
转换 URI 短横线
此选项在自动路由中将短横线(-
)自动转为下划线(因短横线非有效类/方法名字符):
<?php
// In app/Config/Routing.php
use CodeIgniter\Config\Routing as BaseRouting;
// ...
class Routing extends BaseRouting
{
// ...
public bool $translateURIDashes = true;
// ...
}
// This can be overridden in app/Config/Routes.php
$routes->setTranslateURIDashes(true);
备注
在使用自动路由(改进版)时,在 v4.4.0 之前,如果 $translateURIDashes
为 true,两个 URI 对应一个控制器方法,一个 URI 用于破折号(例如 foo-bar),另一个 URI 用于下划线(例如 foo_bar)。这是错误的行为。从 v4.4.0 开始,下划线的 URI(foo_bar)不可访问。
仅使用定义路由
v4.2.0 起默认禁用自动路由。
当未找到与当前 URI 匹配的定义路由时,系统尝试通过自动路由匹配控制器方法。将 $autoRoute
设为 false
可完全禁用自动路由:
<?php
// In app/Config/Routing.php
use CodeIgniter\Config\Routing as BaseRouting;
// ...
class Routing extends BaseRouting
{
// ...
public bool $autoRoute = false;
// ...
}
// This can be overridden in app/Config/Routes.php
$routes->setAutoRoute(false);
警告
启用 CSRF 保护 时,GET 请求不受保护。若 URI 可通过 GET 访问,CSRF 保护将失效。
404 重写
当找不到与当前 URI 匹配的页面时,系统将显示一个通用的 404 页面。通过在路由配置文件中使用 $override404
属性,你可以为 404 路由定义控制器类/方法。
<?php
// In app/Config/Routing.php
use CodeIgniter\Config\Routing as BaseRouting;
// ...
class Routing extends BaseRouting
{
// ...
public ?string $override404 = 'App\Errors::show404';
// ...
}
你还可以在路由配置文件中使用 set404Override()
方法指定在发生 404 错误时执行的操作。该值可以是一个有效的类/方法对,或者是一个闭包:
<?php
// In app/Config/Routes.php
// Would execute the show404 method of the App\Errors class
$routes->set404Override('App\Errors::show404');
// Will display a custom view.
$routes->set404Override(static function () {
// If you want to get the URI segments.
$segments = request()->getUri()->getSegments();
return view('my_errors/not_found.html');
});
备注
从 v4.5.0 开始,404 覆盖功能默认将响应状态代码设置为 404
。在之前的版本中,状态代码是 200
。
如果你想在控制器中更改状态代码,请参见 CodeIgniter\HTTP\Response::setStatusCode()
获取有关如何设置状态代码的信息。
按优先级处理路由
启用或禁用按优先级处理路由队列。在路由选项中降低优先级。默认禁用。 此功能影响所有路由。有关降低优先级的示例用法,请参阅 路由优先级:
<?php
// In app/Config/Routing.php
use CodeIgniter\Config\Routing as BaseRouting;
// ...
class Routing extends BaseRouting
{
// ...
public bool $prioritize = true;
// ...
}
// In app/Config/Routes.php
// to enable
$routes->setPrioritize();
// to disable
$routes->setPrioritize(false);
多 URI 段作为单一参数
在 4.5.0 版本加入.
启用此选项后,匹配多段的占位符(如 (:any)
)将作为单一参数传递(即使包含斜杠):
<?php
// In app/Config/Routing.php
use CodeIgniter\Config\Routing as BaseRouting;
class Routing extends BaseRouting
{
// ...
public bool $multipleSegmentsOneParam = true;
// ...
}
例如路由:
<?php
$routes->get('product/(:any)', 'Catalog::productLookup/$1');
将匹配 product/123、product/123/456、product/123/456/789 等等。
如果 URI 是 product/123/456,123/456
将被传递给 Catalog::productLookup()
方法的第一个参数。
自动路由(改进版)
在 4.2.0 版本加入.
这是更安全的新自动路由系统,详见 自动路由(改进版)。
自动路由(传统版)
重要
这个功能只为了向后兼容而存在。在新项目中不要使用它。即使你已经在使用它,我们也推荐你使用 自动路由(改进版) 替代。
自动路由(传统)是来自 CodeIgniter 3 的路由系统。它可以根据约定自动路由 HTTP 请求,并执行相应的控制器方法。
推荐在 app/Config/Routes.php 文件中定义所有路由,或者使用 自动路由(改进版)。
警告
为了防止配置错误和编码错误,我们建议你不要使用自动路由(传统)功能。很容易创建容易受攻击的应用程序,其中控制器过滤器或 CSRF 保护被绕过。
重要
自动路由(传统)会将任何 HTTP 方法的 HTTP 请求路由到控制器方法。
启用传统自动路由
自 v4.2.0 起,默认禁用自动路由。
要使用它,你需要在 app/Config/Routing.php 中将 $autoRoute
选项设置为 true
:
public bool $autoRoute = true;
并且在 app/Config/Feature.php 中,将属性 $autoRoutesImproved
设置为 false
:
public bool $autoRoutesImproved = false;
URI 分段(传统版)
遵循模型-视图-控制器(MVC)模式,URL 中的各段通常表示:
example.com/class/method/ID
第一段表示应被调用的控制器 class
第二段表示应被调用的类 method
第三段及后续各段表示将传递给控制器的 ID 和其他变量
考虑以下 URI:
example.com/index.php/helloworld/index/1
在上述示例中,CodeIgniter 将尝试查找名为 Helloworld.php 的控制器,并执行 index()
方法,同时传递 '1'
作为第一个参数。
更多信息请参阅 控制器中的自动路由(传统模式)。
配置选项(传统版)
这些选项在 app/Config/Routing.php 文件中可用。
默认控制器(传统版)
针对网站根 URI(传统版)
当用户访问你网站的根(例如,example.com)时,除非存在明确的路由,否则将根据 $defaultController
属性设定的值来确定要使用的控制器。
对于这个属性,默认值是 Home
,它匹配在 app/Controllers/Home.php 的控制器:
public string $defaultController = 'Home';
针对目录 URI(传统版)
默认控制器也在未找到匹配的路由且 URI 指向控制器目录中的目录时使用。例如,如果用户访问 example.com/admin,如果在 app/Controllers/Admin/Home.php 中找到了一个控制器,则会使用它。
更多信息请参阅 控制器中的自动路由(传统)。
默认方法(传统版)
这与默认控制器设置类似,但用于在找到与 URI 匹配的控制器但不存在方法段时确定使用的默认方法。默认值为 index
。
在此示例中,如果用户访问 example.com/products,且存在 Products
控制器,将执行 Products::listAll()
方法:
public string $defaultMethod = ‘listAll’;
验证路由
通过 spark 命令 查看所有路由:
spark 路由
显示所有路由及过滤器:
php spark routes
输出示例:
+---------+---------+---------------+-------------------------------+----------------+---------------+
| Method | Route | Name | Handler | Before Filters | After Filters |
+---------+---------+---------------+-------------------------------+----------------+---------------+
| GET | / | » | \App\Controllers\Home::index | | toolbar |
| GET | feed | » | (Closure) | | toolbar |
+---------+---------+---------------+-------------------------------+----------------+---------------+
Method 列显示路由监听的 HTTP 方法。
Route 列显示要匹配的路由路径。定义路由的路由以正则表达式表示。
自 v4.3.0 起, Name 列显示路由名称。»
表示名称与路由路径相同。
重要
系统并非完美。对于包含如 ([^/]+)
或 {locale}
的正则表达式模式的路由,显示的 Filters 可能不正确(如果你在 app/Config/Filters.php 中为过滤器设置了复杂的 URI 模式),或者它显示为 <unknown>
。
spark filter:check 命令可以用来检查 100% 准确的过滤器。
自动路由(改进版)
当你使用自动路由(改进版)时,输出类似以下内容:
+-----------+-------------------------+---------------+-----------------------------------+----------------+---------------+
| Method | Route | Name | Handler | Before Filters | After Filters |
+-----------+-------------------------+---------------+-----------------------------------+----------------+---------------+
| GET(auto) | product/list/../..[/..] | | \App\Controllers\Product::getList | | toolbar |
+-----------+-------------------------+---------------+-----------------------------------+----------------+---------------+
Method 将显示为 GET(auto)
。
Route 列中的 /..
表示一个段。[/..]
表示可选。
备注
当启用自动路由并且你有 home
路由时,它也可以通过 Home
访问,或者通过 hOme
、hoMe
、HOME
等访问,但是该命令只会显示 home
。
如果你看到以 x
开头的路由,如下所示,这表示一个无效路由,不会路由,但是控制器有公共方法进行路由。
+-----------+----------------+------+-------------------------------------+----------------+---------------+
| Method | Route | Name | Handler | Before Filters | After Filters |
+-----------+----------------+------+-------------------------------------+----------------+---------------+
| GET(auto) | x home/foo | | \App\Controllers\Home::getFoo | <unknown> | <unknown> |
+-----------+----------------+------+-------------------------------------+----------------+---------------+
上面的示例显示你有 \App\Controllers\Home::getFoo()
方法,但是它没有路由,因为它是默认控制器(默认为 Home
),默认控制器名称必须在 URI 中省略。你应该删除 getFoo()
方法。
备注
在 v4.3.4 之前,由于一个错误,无效路由会显示为正常路由。
自动路由(传统)
当你使用自动路由(传统)时,输出类似以下内容:
+--------+--------------------+---------------+-----------------------------------+----------------+---------------+
| Method | Route | Name | Handler | Before Filters | After Filters |
+--------+--------------------+---------------+-----------------------------------+----------------+---------------+
| auto | product/list[/...] | | \App\Controllers\Product::getList | | toolbar |
+--------+--------------------+---------------+-----------------------------------+----------------+---------------+
Method 将显示为 auto
。
Route 列中的 [/...]
表示任意数量的段。
备注
当启用自动路由并且你有 home
路由时,它也可以通过 Home
访问,或者通过 hOme
、hoMe
、HOME
等访问,但是该命令只会显示 home
。
按处理程序排序
在 4.3.0 版本加入.
你可以按 Handler 对路由进行排序:
php spark routes -h
指定主机
在 4.4.0 版本加入.
通过 --host
指定请求主机:
php spark routes --host accounts.example.com
获取路由信息
在 CodeIgniter 4 中,理解和管理路由信息对于有效处理 HTTP 请求至关重要。这涉及到检索有关活动控制器和方法的详细信息,以及应用于特定路由的过滤器。下面,我们探讨如何访问这些路由信息,以帮助完成诸如日志记录、调试或实现条件逻辑等任务。
检索当前控制器/方法名称
在某些情况下,你可能需要确定当前 HTTP 请求触发了哪个控制器和方法。这对于日志记录、调试或基于活动控制器方法的条件逻辑非常有用。
CodeIgniter 4 提供了一种简单的方法来使用 Router
类访问当前路由的控制器和方法名称。以下是一个示例:
<?php
// Get the router instance.
/** @var \CodeIgniter\Router\Router $router */
$router = service('router');
// Retrieve the fully qualified class name of the controller handling the current request.
$controller = $router->controllerName();
// Retrieve the method name being executed in the controller for the current request.
$method = $router->methodName();
echo 'Current Controller: ' . $controller . '<br>';
echo 'Current Method: ' . $method;
当你需要动态地与控制器交互或记录处理特定请求的方法时,这个功能特别有用。
获取当前路由的活动过滤器
过滤器 是一个强大的功能,使你能够在处理 HTTP 请求之前或之后执行诸如身份验证、日志记录和安全检查等操作。要访问特定路由的活动过滤器,你可以使用 Router
类中的 CodeIgniter\Router\Router::getFilters()
方法。
此方法返回当前正在处理的路由的活动过滤器列表:
<?php
// Get the router instance.
/** @var \CodeIgniter\Router\Router $router */
$router = service('router');
$filters = $router->getFilters();
echo 'Active Filters for the Route: ' . implode(', ', $filters);
备注
getFilters()
方法仅返回为特定路由定义的过滤器。
它不包括全局过滤器或在 app/Config/Filters.php 文件中指定的过滤器。