CodeIgniter4 URL路由

2020-08-17 15:12 更新

一般情況下,一個 URL 字符串和它對應(yīng)的控制器中類和方法是一一對應(yīng)的關(guān)系。 URL 中的每一段通常遵循下面的規(guī)則:

example.com/class/function/id/

但是有時候,你可能想改變這種映射關(guān)系,調(diào)用一個不同的類或方法,而不是 URL 中對應(yīng)的那樣。

例如,假設(shè)你希望你的 URL 變成下面這樣:

example.com/product/1/
example.com/product/2/
example.com/product/3/
example.com/product/4/

URL 的第二段通常表示方法的名稱,但在上面的例子中,第二段是一個商品 ID , 為了實(shí)現(xiàn)這一點(diǎn),CodeIgniter 允許你重新定義 URL 的處理流程。

設(shè)置你自己的路由規(guī)則

路由規(guī)則定義在 app/config/Routes.php 文件中。你將會在其中看到,該文件創(chuàng)建了一個RouteCollection類的實(shí)例,這一實(shí)例允許你定義自己的路由規(guī)則。 路由中可使用通配符和正則表達(dá)式。

路由通常將URI置于左側(cè),而將控制器和對應(yīng)的方法以及任何可能存在的,并需要傳遞給控制器的參數(shù)映射在右側(cè)??刂破髋c其方法的列出形式就像你調(diào)用一個類的靜態(tài)方法一樣, 用雙冒號來分隔一個充分命名空間化形式的類與其方法,例如 Users::list。如果這個方法需要被傳遞參數(shù),這些參數(shù)應(yīng)被以正斜杠分割的形式在方法名后列出,如:

// 調(diào)用 $Users->list()
Users::list
// 調(diào)用 $Users->list(1, 23)
Users::list/1/23

通配符

一個典型的路由規(guī)則看上去就像這樣:

$routes->add('product/(:num)', 'App\Catalog::productLookup');

在一個路由中,第一個參數(shù)包含需要被匹配到的URI,而第二個參數(shù)包含著這個路由應(yīng)被定位到的目標(biāo)位置。在上述例子中,當(dāng)單詞”product”在URL的第一個分段中被發(fā)現(xiàn), 同時在第二個分段中出現(xiàn)了一個數(shù)字,那么 App\Catalog 類與 productLookup 方法就會調(diào)用。

通配符是一系列簡單的正則表達(dá)式類型的字符串。在路由處理過程中,通配符會被正則表達(dá)式的值所取代,故而這些通配符主要是為了可讀性而設(shè)計(jì)的。

當(dāng)在你的路由處理過程中,可使用如下通配符:

  • (:any) 將會從當(dāng)前位置開始到URI結(jié)束,匹配任何字符。這一通配符可能會包括多個URI分段。
  • (:segment) 將會匹配除了斜杠(/)以外的任何字符,從而將匹配結(jié)果限制在一個單獨(dú)的分段中。
  • (:num) 將會匹配任何整數(shù)。
  • (:alpha) 將會匹配任何英文字母字符。
  • (:alphanum) 將會匹配任何英文字母或整數(shù),或者是這兩者的組合。
  • (:hash):segment 相同,但可用于方便地查看那個路由正在使用哈希id(參照 Model )。

注解

因?yàn)?{locale} 是一個系統(tǒng)保留關(guān)鍵詞,用于 localization ,所以不可用于通配符或路由的其他部分。

示例

以下是一些路由示例:

$routes->add('journals', 'App\Blogs');

一個第一個分段包含有單詞”journals”的URL將會被映射于 App\Blogs 類,這個類的默認(rèn)方法通常將會是 index():

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

一個包含有 “blog/joe” 的分段的URL將會被映射于 \Blogs 類和 users 方法,而其ID參數(shù)將會被置為34:

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

一個第一個分段為”product”,并且第二個分段是任意字符的URl,將會被映射于 \Catalog 類的 productLookup 方法:

$routes->add('product/(:num)', 'Catalog::productLookupByID/$1';

一個第一個分段為”product”,并且第二個分段是數(shù)字的URl,將會被映射于 \Catalog 類的 productLookup 方法,并將這一數(shù)字傳遞為方法的一個變量參數(shù)。

重要

盡管 add() 方法是相當(dāng)方便的,我們還是推薦使用基于HTTP動詞的路由結(jié)構(gòu),如下所述,并且這也更為安全。

與此同時,這樣也會帶來輕微的性能提升,因?yàn)橹挥衅ヅ洚?dāng)前請求方法的路由會被保存,從而在搜索路由時會減少搜索次數(shù)。

自定義通配符

你也可以在路由文件中創(chuàng)建自己的通配符從而實(shí)現(xiàn)用戶體驗(yàn)和可讀性的定制需求。

你可以使用 addPlaceholder 方法來增加新的通配符。第一個參數(shù)是一個被用來作為通配符的字符串,第二個是該通配符應(yīng)當(dāng)被替換成的正則表達(dá)式。 這一方法操作需要在你增加路由之前被調(diào)用:

$routes->addPlaceholder('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}');
$routes->add('users/(:uuid)', 'Users::show/$1');

正則表達(dá)式

如果你更傾向于使用正則表達(dá)式的話,也可以用它來定義路由規(guī)則。允許任何有效的正則表達(dá)式,例如反向引用。

重要

Note:如果你使用逆向引用,你需要使用美元符號代替雙斜線語法。一個典型的使用正則表達(dá)式的路由規(guī)則看起來像下面這樣:


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

上例中,一個類似于 products/shirts/123 這樣的 URL 將會重定向到 Products 控制器的 show 方法。 并且將原來的第一個第二個URI分段作為參數(shù)傳遞給它。通過正則表達(dá)式,你也可以捕獲一個帶有斜杠(’/’)的分段,而通常來說 斜杠是用于多個分段時間的分隔符。

例如,當(dāng)一個用戶訪問你的 Web 應(yīng)用中的某個受密碼保護(hù)的頁面時,如果他沒有 登陸,會先跳轉(zhuǎn)到登陸頁面,你希望在他們在成功登陸后重定向回剛才那個頁面, 那么這個例子會很有用:

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

對于諸位雖然不熟悉正則表達(dá)式而又想了解更多關(guān)于正則表達(dá)式的,W3Cschool的 正則表達(dá)式 教程可能是一個不錯的起點(diǎn)。

重要

注意:你也可以在你的路由規(guī)則中混用通配符和正則表達(dá)式。

閉包

你可以使用一個匿名函數(shù),或者閉包,作為路由的映射目標(biāo)位置。這一函數(shù)將會在用戶訪問指定URI時執(zhí)行。 以上操作在執(zhí)行小功能,或只是顯示一個簡單的視圖時,是相當(dāng)方便的:

$routes->add('feed', function()
{
    $rss = new RSSFeeder();
    return $rss->feed('general');
});

映射多個路由

雖然add()方法非常簡單易用,但是調(diào)用 map() 方法來同時處理多個路由通常更為方便。 你可以通過定義一個路由的數(shù)組,并將其作為 map() 方法的第一個參數(shù)的批量處理的方式,來取代每次都要用 add() 方法來添加所需要路由:

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


$collection->map($routes);

重定向路由

任何存在了足夠長時間的網(wǎng)站都肯定存在移動過的頁面。你可以通過 addRedirect() 方法來重定向需要跳轉(zhuǎn)到其他路由的路由規(guī)則。 第一個參數(shù)是原有的路由的URI規(guī)則,第二個參數(shù)是新的URI,或者是一個命名路由的名稱。第三個參數(shù)是隨著重定向一起發(fā)送的狀態(tài)碼, 默認(rèn)值 302 ,這也是通常情況下用的比較多的,意味著暫時的重定向:

$routes->add('users/profile', 'Users::profile', ['as' => 'profile']);


// 重定向至命名路由
$routes->addRedirect('users/about', 'profile');
// 重定向至URI
$routes->addRedirect('users/about', 'users/profile');

當(dāng)頁面加載時,若匹配到重定向路由,則用戶將會在加載原有控制器之前被重定向到新頁面。

分組路由

你可以使用 group() 將你的路由分組并設(shè)定一個通用的名字。分組名將作為URI的一個分段,用于組內(nèi)所有定義的路由之前。 這一方式可以幫助你在定義一大組有相同前綴的路由時,減少額外的打字輸入,例如設(shè)置一個管理分組時:

$routes->group('admin', function($routes)
{
        $routes->add('users', 'Admin\Users::index');
        $routes->add('blog', 'Admin\Blog::index');
});

如上,’users’和’blog’這些URI就會加上”amdin”的前綴,從而處理例如 /admin/users/admin/blog 的URI。 如果你需要的話,同樣也可以嵌套分組以便管理:

$routes->group('admin', function($routes)
{
        $routes->group('users', function($routes)
        {
                $routes->add('list', 'Admin\Users::list');
        });


});

這將用于處理例如 admin/users/list 的URI。

如果你需要為一個分組指定指定選項(xiàng),類似 namespace ,請?jiān)诨卣{(diào)前使用:

$routes->group('api', ['namespace' => 'App\API\v1'], function($routes)
{
        $routes->resource('users');
});

這將能夠使得如同 /api/users/ 一樣resource的路由映射于 App\API\v1\Users 控制器上。 你也可以對一組路由使用一個特定的過濾器。過濾器總是會在控制器的調(diào)用前或調(diào)用后運(yùn)行,這一操作在認(rèn)證或api日志時格外有用:

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

控制器的值必須與定義在 app/Config/Filters.php 中的一系列別名中的至少一個所匹配。

環(huán)境約束

你可以設(shè)置一組在特定環(huán)境下運(yùn)行的路由。這方便了你創(chuàng)建一組只有開發(fā)者在本地環(huán)境中可使用,而在測試和生產(chǎn)環(huán)境不可見的工具。 以上操作可通過 environment() 方法來實(shí)現(xiàn)。第一個參數(shù)是環(huán)境名。在這個閉包中的定義的所有路由,僅在當(dāng)前環(huán)境下可訪問:

$routes->environment('development', function($routes)
{
        $routes->add('builder', 'Tools\Builder::index');
});

反向路由

反向路由允許你定義一個鏈接與它需要查找的當(dāng)前路由所需要使用的控制器和方法以及參數(shù)。這可以不需要改變程序代碼而定義路由規(guī)則。通常用于視圖內(nèi)部以創(chuàng)建鏈接地址。

舉例來說,如果你需要一個跳轉(zhuǎn)到圖片相冊的路由,你可以使用 route_to() 輔助函數(shù)以獲取當(dāng)前應(yīng)該使用的路由。 第一個參數(shù)是完整的控制器類名與方法名以雙英文冒號(::)區(qū)分,就像你在寫一條原生的路由規(guī)則的格式一樣。其他所有需要傳遞給這個路由的參數(shù)都將在后面被傳遞:

// 該路由定義為:
$routes->add('users/(:id)/gallery(:any)', 'App\Controllers\Galleries::showUserGallery/$1/$2');


// 生成對應(yīng)連接到用戶ID1:5,圖片ID:12的指定URL
// 生成:/users/15/gallery/12
<a href="<?= route_to('App\Controllers\Galleries::showUserGallery', 15, 12) ?>">查看相冊</a>

使用命名路由

你可以為路由命名,從而提高系統(tǒng)健壯性(魯棒性),這一操作可通過給一個路由命名從而在后面調(diào)用來實(shí)現(xiàn)。 即使路由定義改變了,所有在系統(tǒng)中通過 route_to 創(chuàng)建的的連接將仍舊可用并且不需要進(jìn)行任何變動。 命名一個路由,通過與路由名一起傳遞 as 選項(xiàng)來實(shí)現(xiàn):

// 路由定義為:
$routes->add('users/(:id)/gallery(:any)', 'Galleries::showUserGallery/$1/$2', ['as' => 'user_gallery');


// 生成對應(yīng)連接到用戶ID1:5,圖片ID:12的指定URL
    // 生成:/users/15/gallery/12
<a href="<?= route_to('user_gallery', 15, 12) ?>">View Gallery</a>

這同樣使得視圖更具有可讀性。

在路由中使用 HTTP 動詞

還可以在你的路由規(guī)則中使用 HTTP 動詞(請求方法),當(dāng)你在創(chuàng)建 RESTFUL 應(yīng)用時特別有用。 你可以使用所有標(biāo)準(zhǔn)的 HTTP 動詞(GET、PUT、POST、DELETE等),每個動詞都擁有自己對應(yīng)的方法供你使用:

$routes->get('products', 'Product::feature');
$routes->post('products', 'Product::feature');
$routes->put('products/(:num)', 'Product::feature');
$routes->delete('products/(:num)', 'Product::feature');

你可以指定一個路由可以匹配多個動詞,將其傳遞 match() 方法作為一個數(shù)組:

$routes->match(['get', 'put'], 'products', 'Product::feature');

命令行專用的路由

你可以使用 cli() 方法來創(chuàng)建命令行專用,瀏覽器不可訪問的路由。 這一方法中創(chuàng)建crojobs(定時任務(wù))或命令行工具時相當(dāng)有效。 而基于HTTP動詞的路由同樣對于命令行也是不可訪問的,除了通過 any() 方法創(chuàng)建的路由之外:

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

全局選項(xiàng)

所有用于創(chuàng)建路由的方法(例如add, get, post, resource 等)都可以調(diào)用一個選項(xiàng)數(shù)組來修改已生成的路由或限制它們的規(guī)則。而這一數(shù)組 $options 就是這些方法的最后一個參數(shù):

$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, function());

應(yīng)用過濾器

你可以通過指定一個過濾器在控制器調(diào)用前或調(diào)用后運(yùn)行的方式來改變指定路由的行為,這一操作通常在鑒權(quán)或API記錄日志時非常有用:

$routes->add('admin',' AdminController::index', ['filter' => 'admin-auth']);

過濾器的值必須至少匹配 app/Config/Filters.php 中的一個別名。 你也可以指定過濾器的 before()after() 方法的參數(shù):

$routes->add('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']);

瀏覽 Controller filters 來獲取更多有關(guān)設(shè)置篩選過濾器的信息。

指定命名空間

盡管默認(rèn)的命名空間會在生成的控制器前自動附加(如下),你也可以通過 namespace 選項(xiàng)來指定一個別的命名空間在選項(xiàng)數(shù)組中。 選項(xiàng)值應(yīng)該與你想指定的命名空間一致:

// 路由指定至 \Admin\Users::index()
    $routes->add('admin/users', 'Users::index', ['namespace' => 'Admin']);

新的命名空間僅應(yīng)用于創(chuàng)建一個單獨(dú)路由的方法調(diào)用中,例如get, post等。對于創(chuàng)建多個路由的方法,新的命名空間將會被附在所有被這個方法鎖生成的路由之前,例如在 group() 中,所有的路由都是在閉包中生成的。

限制域名

你可以通過給選項(xiàng)數(shù)組的”hostname”選項(xiàng)傳一個域名作為值的形式來限制一組路由只在你的應(yīng)用的特定域名或子域名下生效:

$collection->get('from', 'to', ['hostname' => 'accounts.example.com']);

這個例子僅允許當(dāng)前訪問的路由在域名為”accounts.example.com”時生效,而在其主域名”example.com”下無法生效。

限制子域名

當(dāng) subdomain 選項(xiàng)開啟時,系統(tǒng)將會限制路由僅在此子域名生效。只有在訪問該子域名時系統(tǒng)才會匹配這組路由規(guī)則:

// 限制子域名為media.example.com
$routes->add('from', 'to', ['subdomain' => 'media']);

你可以通過設(shè)置該選項(xiàng)值為星號(*)的方式來對所有子域名生效。當(dāng)你訪問的URL不匹配任何子域名時,這項(xiàng)路由將不會被匹配到:

// 限制所有子域名訪問
$routes->add('from', 'to', ['subdomain' => '*']);

重要

系統(tǒng)不是完美無缺的,所以在部署生產(chǎn)環(huán)境前需要在特定的子域名下進(jìn)行測試。大多數(shù)域名都沒有問題,但在一些邊緣情況下,特別是某些域名本身中就含有點(diǎn)號(.),而這個點(diǎn)號又不是拿來區(qū)分前綴或者后綴時,就可能會出錯。

Offsetting the Matched Parameters

你可以向后推移在路由中匹配到的參數(shù)的位置,通過在 offset 選項(xiàng)中傳遞任何數(shù)字值,該值指名了推移匹配的URI分段的數(shù)量。

這將會為開發(fā)API帶來好處,當(dāng)URI第一個分段是版本號時,同樣可以用于第一個參數(shù)是一個語言標(biāo)識(例如en,fr等,譯者注):

$routes->get('users/(:num)', 'users/show/$1', ['offset' => 1]);


// 創(chuàng)建:
$routes['users/(:num)'] = 'users/show/$2';

(譯者注:實(shí)質(zhì)就是將匹配的位置向后推移,由于第一個分段的位置可能會被其他參數(shù)占用,所以通配符的位置需要后移, 例如/en/users/(:num),這里/en/是第一個分段,不需要作為路由使用,所以(:num)實(shí)際上通過offset后移到了$2的位置。)

路由配置選項(xiàng)

路由集合類提供了多個可影響到所有路由的選項(xiàng)配置,并可被修改以符合程序要求,這些選項(xiàng)可在 /app/Config/Routes/php 文件的頂部被更改。

默認(rèn)命名空間

當(dāng)匹配到了一個需要路由的控制器,路由將會為該控制器增加一個默認(rèn)的命名空間。默認(rèn)設(shè)置下,這個命名空間的值為空,從而每個每個路由都需要完全對應(yīng)到的帶有命名空間的控制器類名:

$routes->setDefaultNamespace('');


// 控制器為 \Users
$routes->add('users', 'Users::index');


// 控制器為 \Admin\Users
$routes->add('users', 'Admin\Users::index');

如果你的控制器不是嚴(yán)格遵從命名空間的話,就沒有更改的必要。如果你為控制器指定了命名空間,就可以通過更改默認(rèn)命名空間的值來減少打字輸入:

$routes->setDefaultNamespace('App');


// 控制器為 \App\Users
$routes->add('users', 'Users::index');


// 控制器為 \App\Admin\Users
$routes->add('users', 'Admin\Users::index');

默認(rèn)控制器

當(dāng)用戶直接訪問你的站點(diǎn)的根路徑時(例如example.com),所調(diào)用的控制器將會由 setDefaultController() 方法所設(shè)置的參數(shù)決定,除非有一個路由是顯式聲明過(默認(rèn)控制器)。 這一方法的默認(rèn)值是 Home ,對應(yīng)的控制器是 /app/Controllers/Home.php

// example.com 對應(yīng)的路由是app/Controllers/Welcome.php
$routes->setDefaultController('Welcome');

默認(rèn)控制器同樣也在找不到對應(yīng)的路由規(guī)則,URI對應(yīng)到控制器的對應(yīng)目錄下的情況下被用到。 例如有個用戶訪問了 example.com/admin ,如果有個控制器被命名為 /app/Controllers/admin/Home.php ,那么就被調(diào)用到。

默認(rèn)方法

與默認(rèn)控制器的設(shè)置類似,用于設(shè)置設(shè)置默認(rèn)方法。其應(yīng)用場景是,找到了URI對應(yīng)的控制器,但是URI分段對應(yīng)不上控制器的方法時。默認(rèn)值是 index

$routes->setDefaultMethod('listAll');

在這個例子中,當(dāng)用戶訪問example.com/products時,Products控制器存在,從而執(zhí)行 Products::listAll() 方法。

連字符(-)轉(zhuǎn)換

從它的布爾值就能看出來這其實(shí)并不是一個路由,這個選項(xiàng)可以自動的將 URL 中的控制器和方法中的連字符(’-‘)轉(zhuǎn)換為下劃線(’_’),當(dāng)你需要這樣時, 它可以讓你少寫很多路由規(guī)則。由于連字符不是一個有效的類名或方法名, 如果你不使用它的話,將會引起一個嚴(yán)重錯誤:

$routes->setTranslateURIDashes(true);

僅使用定義路由

當(dāng)指定的URI映射不到定義的路由時,系統(tǒng)將會將URI映射到如上所述的控制器和方法。 你可以通過設(shè)置 setAutoRoute() 選項(xiàng)為false的方式來關(guān)閉這一自動映射,并限制系統(tǒng)僅使用你定義的路由:

$routes->setAutoRoute(false);

404 重載

如果當(dāng)前URI匹配不到對應(yīng)的頁面,系統(tǒng)將輸出一個通用的404視圖。你可以通過使用 set404Override() 方法,定義一個操作來改變以上行為。 這一方法的參數(shù)可以是一個合法的類/方法的組合,就如同你在任何路由或者閉包中定義的一樣:

// 將執(zhí)行App\Errors類的show404方法
$routes->set404Override('App\Errors::show404');


// 將會輸出一個自定義的視圖
$routes->set404Override(function()
{
    echo view('my_errors/not_found.html');
});
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號