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');

示例

以下是一些基本的路由示例。

包含单词 **journals** 的 URL 将映射到 \App\Controllers\Blogs 类,以及默认方法,通常是 index()

<?php

$routes->get('journals', 'Blogs');

包含段落 **blog/joe** 的 URL 将映射到 \App\Controllers\Blogs 类和 users() 方法。ID 将设置为 34

<?php

$routes->get('blog/joe', 'Blogs::users/34');

以 **product** 作为第一个段落,第二个段落为任何内容的 URL 将映射到 \App\Controllers\Catalog 类和 productLookup() 方法

<?php

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

以 **product** 作为第一个段落,第二个段落为数字的 URL 将映射到 \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() 方法来指定路由应匹配的多个动词

<?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;,控制器类名将被解释为 Config\Home,而不是 App\Controllers\Home,因为 app/Config/Routes.php 在顶部有 namespace Config;

注意

当您使用数组可调用语法时,类名始终被解释为完全限定的类名。因此,默认命名空间命名空间选项 不会产生任何影响。

数组可调用语法和占位符

如果有占位符,它将自动按指定顺序设置参数

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 结尾的所有字符。这可能包括多个 URI 段。

(:segment)

将匹配除正斜杠 (/) 之外的任何字符,将结果限制为单个段。

(:num)

将匹配任何整数。

(:alpha)

将匹配任何字母字符字符串

(:alphanum)

将匹配任何字母字符或整数字符串,或两者的任何组合。

(:hash)

(:segment) 相同,但可用于轻松查看哪些路由使用哈希 ID。

注意

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

(:any) 的行为

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

例如,路由

<?php

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

将匹配 **product/123**、**product/123/456**、**product/123/456/789** 等等。

在上面的示例中,如果 $1 占位符包含斜杠 (/),它仍然会在传递给 Catalog::productLookup() 时被拆分为多个参数。

控制器中的实现应考虑最大参数

<?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)。使用上面的示例 URL

<?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');

正则表达式

如果您愿意,可以使用正则表达式来定义您的路由规则。任何有效的正则表达式都是允许的,反向引用也是如此。

重要

注意:如果您使用反向引用,则必须使用美元符号语法而不是双反斜杠语法。一个典型的 RegEx 路由可能看起来像这样

<?php

$routes->get('products/([a-z]+)/(\d+)', 'Products::show/$1/id_$2');

在上面的示例中,类似于 **products/shirts/123** 的 URI 将改为调用 Products 控制器类的 show() 方法,并将原始的第一和第二个段作为参数传递给它。

使用正则表达式,您还可以捕获包含正斜杠 (/) 的段,该正斜杠通常表示多个段之间的分隔符。

例如,如果用户访问了您 Web 应用程序的密码保护区域,并且您希望在他们登录后将他们重定向回同一页面,您可能会发现此示例很有用。

<?php

$routes->get('login/(.+)', 'Auth::login/$1');

在上面的示例中,如果 $1 占位符包含斜杠 (/),它仍然会在传递给 Auth::login() 时被拆分为多个参数。

对于那些不了解正则表达式并希望了解更多的人,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(重定向到的 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 动词的路由

重要

此方法仅出于向后兼容性而存在。不要在新项目中使用它。即使您已经在使用它,我们建议您使用其他更合适的方法。

警告

虽然 add() 方法看起来很方便,但建议始终使用上面描述的基于 HTTP 动词的路由,因为它更安全。如果您使用 CSRF 保护,它不会保护 GET 请求。如果 add() 方法中指定的 URI 可以通过 GET 方法访问,则 CSRF 保护将不起作用。

可以定义使用任何 HTTP 动词的路由。您可以使用 add() 方法

<?php

$routes->add('products', 'Product::feature');

注意

使用基于 HTTP 动词的路由也会带来轻微的性能提升,因为只有与当前请求方法匹配的路由才会被存储,从而在尝试找到匹配项时减少要扫描的路由数量。

映射多个路由

重要

此方法仅出于向后兼容性而存在。不要在新项目中使用它。即使您已经在使用它,我们建议您使用其他更合适的方法。

警告

map() 方法与 add() 一样不推荐使用,因为它在内部调用 add()

虽然 add() 方法使用起来很简单,但使用 map() 方法一次处理多个路由通常更方便。与其为每个需要添加的路由调用 add() 方法,不如定义一个路由数组,然后将其作为第一个参数传递给 map() 方法。

<?php

$multipleRoutes = [
    'product/(:num)'      => 'Catalog::productLookupById',
    'product/(:alphanum)' => 'Catalog::productLookupByName',
];

$routes->map($multipleRoutes);

仅限命令行路由

注意

建议使用 Spark 命令来创建 CLI 脚本,而不是通过 CLI 调用控制器。有关详细信息,请参阅 创建 Spark 命令 页面。

任何通过基于 HTTP 动词的路由方法创建的路由都无法从 CLI 访问,但通过 add() 方法创建的路由仍然可以通过命令行访问。

您可以使用 cli() 方法创建仅从命令行工作且无法从 Web 浏览器访问的路由。

<?php

$routes->cli('migrate', 'App\Database::migrate');

警告

如果您启用了 自动路由(旧版) 并将命令文件放在 app/Controllers 中,任何人都可以通过自动路由(旧版)通过 HTTP 访问该命令。

全局选项

所有用于创建路由的方法(get()post()resource() 等)都可以接受一个选项数组,这些选项可以修改生成的路由或进一步限制它们。 $options 数组始终是最后一个参数。

<?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 中新增。

重要

多个过滤器 默认情况下是禁用的。因为它破坏了向后兼容性。如果您想使用它,您需要配置。有关详细信息,请参阅 路由的多个过滤器

您为过滤器值指定一个数组

<?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** 的主站点下工作。

限制到子域名

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' => '*']);

重要

系统并不完美,应该在生产环境中使用之前针对您的特定域名进行测试。大多数域名应该可以正常工作,但一些边缘情况,尤其是域名本身中包含句点(不用于分隔后缀或 www)可能会导致误报。

偏移匹配的参数

您可以使用 offset 选项将匹配的参数偏移任何数值,该值是偏移的段数。

这在开发第一个 URI 段是版本号的 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 控制器使用 api/users URI 的资源路由。

设置过滤器

您还可以为一组路由使用特定的 过滤器。这将在控制器之前或之后始终运行过滤器。这在身份验证或 API 日志记录期间特别有用

<?php

$routes->group('api', ['filter' => 'api-auth'], static function ($routes) {
    $routes->resource('users');
});

过滤器的值必须与 app/Config/Filters.php 中定义的别名之一匹配。

设置其他选项

在某些情况下,您可能希望将路由分组以应用过滤器或其他路由配置选项,例如命名空间、子域等。无需为组添加前缀,您可以传递一个空字符串来代替前缀,并且组中的路由将像组从未存在一样进行路由,但具有给定的路由配置选项

<?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', static function ($routes) {
    $routes->group('users', static function ($routes) {
        $routes->get('list', 'Admin\Users::list');
    });
});

这将处理 admin/users/list 的 URL。

注意

传递给外部 group() 的选项(例如 namespacefilter)不会与内部 group() 选项合并。

路由优先级

路由按照定义顺序注册到路由表中。这意味着当访问 URI 时,将执行第一个匹配的路由。

警告

如果路由路径定义多次,但使用不同的处理程序,则只注册第一个定义的路由。

可以通过运行 spark routes 命令来查看路由表中的注册路由。

更改路由优先级

在处理模块时,如果应用程序中的路由包含通配符,可能会出现问题。然后模块路由将无法正确处理。可以使用 priority 选项降低路由处理的优先级来解决此问题。该参数接受正整数和零。在 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。负整数将转换为绝对值。

路由配置选项

RoutesCollection 类提供了一些影响所有路由的选项,可以修改这些选项以满足应用程序的需求。这些选项在 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');

翻译 URI 连字符

此选项允许您在自动路由中使用时,自动将控制器和方法 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 为真,则两个 URI 对应于一个控制器方法,一个 URI 用于连字符(例如,foo-bar),另一个 URI 用于下划线(例如,foo_bar)。这是不正确的行为。从 v4.4.0 开始,下划线 URI (foo_bar) 不可访问。

仅使用已定义的路由

从 v4.2.0 开始,自动路由默认情况下已禁用。

当没有找到与 URI 匹配的已定义路由时,系统将在启用自动路由时尝试将该 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 视图。您可以通过使用 set404Override() 方法指定要执行的操作来更改发生的事情。该值可以是有效的类/方法对(就像您在任何路由中显示的那样),也可以是闭包。

<?php

// In app/Config/Routing.php
use CodeIgniter\Config\Routing as BaseRouting;

// ...
class Routing extends BaseRouting
{
    // ...
    public ?string $override404 = 'App\Errors::show404';
    // ...
}

// 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 () {
    echo view('my_errors/not_found.html');
});

在路由配置文件中使用 $override404 属性,您可以使用闭包。在路由文件中定义覆盖范围仅限于类/方法对。

注意

set404Override() 方法不会将响应状态代码更改为 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);

自动路由(改进)

版本 4.2.0 中的新增功能。

从 v4.2.0 开始,引入了新的更安全的自动路由。

注意

如果您熟悉自动路由(从 CodeIgniter 3 到 4.1.x 默认启用),您可以在 ChangeLog v4.2.0 中查看差异。

当没有找到与 URI 匹配的已定义路由时,系统将在启用自动路由时尝试将该 URI 与控制器和方法匹配。

重要

出于安全原因,如果在定义的路由中使用控制器,则自动路由(改进)不会路由到控制器。

自动路由可以根据约定自动路由 HTTP 请求并执行相应的控制器方法。

注意

自动路由(改进)默认情况下禁用。要使用它,请参见以下内容。

启用自动路由

要使用它,您需要将设置 $autoRoute 选项更改为 true,位于 app/Config/Routing.php

public bool $autoRoute = true;

您还需要将属性 $autoRoutesImproved 更改为 true,位于 app/Config/Feature.php

public bool $autoRoutesImproved = true;

URI 段

URL 中的段,遵循模型-视图-控制器方法,通常代表

example.com/class/method/ID
  1. 第一个段代表应该调用的控制器 **类**。

  2. 第二部分代表应调用的类**方法**。

  3. 第三部分以及任何附加部分代表将传递给控制器的 ID 和任何变量。

考虑以下 URI

example.com/index.php/helloworld/hello/1

在上面的示例中,当您使用**GET**方法发送 HTTP 请求时,自动路由将尝试查找名为App\Controllers\Helloworld的控制器,并执行getHello()方法,并将'1'作为第一个参数传递。

注意

将由自动路由(改进版)执行的控制器方法需要 HTTP 动词(getpostput等)前缀,例如getIndex()postCreate()

有关更多信息,请参见控制器中的自动路由

配置选项

这些选项在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 访问默认控制器。当默认控制器为 Home 时,您可以访问 **example.com/**,但如果您访问 **example.com/home**,则会找不到。

有关更多信息,请参见控制器中的自动路由

默认方法

这与默认控制器设置类似,但用于确定当找到与 URI 匹配的控制器但没有方法段时使用的默认方法。默认值为 index

在此示例中,如果用户访问 **example.com/products**,并且存在 Products 控制器,则将执行 Products::getListAll() 方法。

public string $defaultMethod = 'listAll';

重要

您不能使用默认方法名称的 URI 访问控制器。在上面的示例中,您可以访问 **example.com/products**,但如果您访问 **example.com/products/listall**,则会找不到。

模块路由

版本 4.4.0 中的新功能。

即使您使用 代码模块 并在不同的命名空间中放置控制器,您也可以使用自动路由。

要路由到模块,必须在 **app/Config/Routing.php** 中设置 $moduleRoutes 属性。

public array $moduleRoutes = [
    'blog' => 'Acme\Blog\Controllers',
];

键是模块的第一个 URI 段,值是控制器命名空间。在上面的配置中,**http://localhost:8080/blog/foo/bar** 将路由到 Acme\Blog\Controllers\Foo::getBar()

注意

如果您定义了 $moduleRoutes,则模块的路由优先。在上面的示例中,即使您拥有 App\Controllers\Blog 控制器,**http://localhost:8080/blog** 也会路由到默认控制器 Acme\Blog\Controllers\Home

自动路由(旧版)

重要

此功能仅出于向后兼容性而存在。不要在新项目中使用它。即使您已经在使用它,我们建议您使用 自动路由(改进版) 代替。

自动路由(旧版)是 CodeIgniter 3 中的路由系统。它可以根据约定自动路由 HTTP 请求并执行相应的控制器方法。

建议将所有路由定义在 **app/Config/Routes.php** 文件中,或使用 自动路由(改进版)

警告

为了防止配置错误和代码错误,我们建议您不要使用自动路由(旧版)功能。它很容易创建容易受到攻击的应用程序,其中控制器过滤器或 CSRF 保护被绕过。

重要

自动路由(旧版)将具有 **任何** HTTP 方法的 HTTP 请求路由到控制器方法。

启用自动路由(旧版)

从 v4.2.0 开始,自动路由默认情况下已禁用。

要使用它,您需要将设置 $autoRoute 选项更改为 true,位于 app/Config/Routing.php

public bool $autoRoute = true;

并在 **app/Config/Feature.php** 中将属性 $autoRoutesImproved 设置为 false

public bool $autoRoutesImproved = false;

URI 段(旧版)

URL 中的段,遵循模型-视图-控制器方法,通常代表

example.com/class/method/ID
  1. 第一个段代表应该调用的控制器 **类**。

  2. 第二部分代表应调用的类**方法**。

  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';

确认路由

CodeIgniter 有以下 命令 用于显示所有路由。

spark routes

显示所有路由和过滤器

php spark routes

输出类似于以下内容

+---------+---------+---------------+-------------------------------+----------------+---------------+
| Method  | Route   | Name          | Handler                       | Before Filters | After Filters |
+---------+---------+---------------+-------------------------------+----------------+---------------+
| GET     | /       | »             | \App\Controllers\Home::index  |                | toolbar       |
| GET     | feed    | »             | (Closure)                     |                | toolbar       |
+---------+---------+---------------+-------------------------------+----------------+---------------+

方法 列显示了路由正在监听的 HTTP 方法。

路由 列显示了要匹配的路由路径。定义的路由的路由以正则表达式表示。

从 v4.3.0 开始,名称 列显示了路由名称。 » 表示名称与路由路径相同。

重要

系统并不完美。对于包含正则表达式模式的路由,例如 ([^/]+){locale},显示的 过滤器 可能不正确(如果您在 **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       |
+-----------+-------------------------+---------------+-----------------------------------+----------------+---------------+

方法 将类似于 GET(auto)

/..路由 列中表示一个段。 [/..] 表示它是可选的。

注意

当启用自动路由并且您有路由 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       |
+--------+--------------------+---------------+-----------------------------------+----------------+---------------+

方法将为 auto

[/...]路由 列中表示任意数量的段。

注意

当启用自动路由并且您有路由 home 时,它也可以通过 Home 访问,或者可能通过 hOmehoMeHOME 等访问,但命令只会显示 home

按处理程序排序

版本 4.3.0 中新增。

您可以按 处理程序 排序路由

php spark routes -h

指定主机

版本 4.4.0 中的新功能。

您可以使用 --host 选项在请求 URL 中指定主机

php spark routes --host accounts.example.com