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)

(:segment) 相同,便于识别使用哈希 ID 的路由

备注

{locale} 不能作为占位符或路由其他部分,保留用于 本地化

(:any) 的行为

注意单个 (:any) 会匹配 URL 中的多个段(如果存在)。

例如路由:

<?php

$routes->get('product/(:any)', 'Catalog::productLookup/$1');

将匹配 product/123product/123/456product/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');
});

这将会为 usersblog URI 添加 admin 前缀,处理如 admin/usersadmin/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:configmyfilter2: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';

备注

$defaultMethod 也常用于自动路由。 请参见 自动路由(改进版)自动路由(传统版)

如果你定义了以下路由:

$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/123product/123/456product/123/456/789 等等。 如果 URI 是 product/123/456123/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
  1. 第一段表示应被调用的控制器 class

  2. 第二段表示应被调用的类 method

  3. 第三段及后续各段表示将传递给控制器的 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 访问,或者通过 hOmehoMeHOME 等访问,但是该命令只会显示 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 访问,或者通过 hOmehoMeHOME 等访问,但是该命令只会显示 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 文件中指定的过滤器。