路由
路由
路由
基本路由
構建基本的路由只需要一個 URI 與一個 閉包
,這里提供了一個非常簡單優(yōu)雅定義路由的方法:
Route::get('foo', function () { return 'Hello World'; });
默認路由文件
所有的 Laravel 路由都在 routes
目錄中的路由文件中定義,這些文件都由框架自動加載。routes/web.php
文件用于定義 web
界面的路由。這里面的路由都會被分配給 web
中間件組,它提供了會話狀態(tài)和 CSRF 保護等功能。定義在 routes/api.php
中的路由都是無狀態(tài)的,并且被分配了 api
中間件組。
大多數(shù)的應用構建,都是以在 routes/web.php
文件定義路由開始的??梢酝ㄟ^在瀏覽器中輸入定義的路由 URL 來訪問 routes/web.php
中定義的路由。例如,你可以在瀏覽器中輸入 http://your-app.dev/user
來訪問以下路由
Route::get('/user', 'UserController@index');
routes/api.php
文件中定義的路由通過 RouteServiceProvider
被嵌套到一個路由組里面。在這個路由組中,會自動添加 URL 前綴 /api
到此文件中的每個路由,這樣你就無需再手動添加了。你可以在 RouteServiceProvider
類中修改此前綴以及其他路由組選項。
可用的路由方法
路由器允許你注冊能響應任何 HTTP 請求的路由:
Route::get($uri, $callback); Route::post($uri, $callback); Route::put($uri, $callback); Route::patch($uri, $callback); Route::delete($uri, $callback); Route::options($uri, $callback);
有的時候你可能需要注冊一個可響應多個 HTTP 請求的路由,這時你可以使用 match
方法,也可以使用 any
方法注冊一個實現(xiàn)響應所有 HTTP 請求的路由:
Route::match(['get', 'post'], '/', function () { // }); Route::any('foo', function () { // });
CSRF 保護
指向 web
路由文件中定義的 POST
、PUT
或 DELETE
路由的任何 HTML 表單都應該包含一個 CSRF 令牌字段,否則,這個請求將會被拒絕??梢栽?CSRF 文檔 中閱讀有關 CSRF 更多的信息:
<form method="POST" action="/profile"> @csrf ... </form>
重定向路由
如果要定義重定向到另一個 URI 的路由,可以使用 Route::redirect
方法。這個方法可以快速的實現(xiàn)重定向,而不再需要去定義完整的路由或者控制器:
Route::redirect('/here', '/there');
Route::redirect
默認會返回狀態(tài)碼 302
。 你可以通過第三個參數(shù)自定義返回碼:
Route::redirect('/here', '/there', 301);
你也可以使用 Route::permanentRedirect
方法來返回 301
狀態(tài)碼:
Route::permanentRedirect('/here', '/there');
視圖路由
如果你的路由只需要返回一個視圖,可以使用 Route::view
方法。它和 redirect
一樣方便,不需要定義完整的路由或控制器。view
方法有三個參數(shù),其中第一個是必填參數(shù),是包含視圖名稱的 URI 。第二個也是必填參數(shù),是需要渲染的視圖名稱。第三個參數(shù)是可選參數(shù),可以傳入一個數(shù)組,數(shù)組中的數(shù)據(jù)會被傳遞給視圖:
Route::view('/welcome', 'welcome'); Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
路由參數(shù)
必填參數(shù)
當然,有時需要在路由中捕獲一些 URL 片段。例如,從 URL 中捕獲用戶的 ID,可以通過定義路由參數(shù)來執(zhí)行此操作:
Route::get('user/{id}', function ($id) { return 'User '.$id; });
也可以根據(jù)需要在路由中定義多個參數(shù):
Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) { // });
路由的參數(shù)通常都會被放在 {}
內(nèi),并且參數(shù)名只能為字母,同時路由參數(shù)不能包含 -
符號,如果需要可以用下劃線 (_
) 代替。路由參數(shù)會按順序依次被注入到路由回調(diào)或者控制器中,而不受回調(diào)或者控制器的參數(shù)名稱的影響。
可選參數(shù)
有時,你可能需要指定一個路由參數(shù),但你希望這個參數(shù)是可選的。你可以在參數(shù)后面加上 ?
標記來實現(xiàn),但前提是要確保路由的相應變量有默認值
Route::get('user/{name?}', function ($name = null) { return $name; }); Route::get('user/{name?}', function ($name = 'John') { return $name; });
正則表達式約束
你可以使用路由實例上的 where
方法約束路由參數(shù)的格式。where
方法接受參數(shù)名稱和定義參數(shù)應如何約束的正則表達式:
Route::get('user/{name}', function ($name) { // })->where('name', '[A-Za-z]+'); Route::get('user/{id}', function ($id) { // })->where('id', '[0-9]+'); Route::get('user/{id}/{name}', function ($id, $name) { // })->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
全局約束
如果你希望某個具體的路由參數(shù)都遵循同一個正則表達式的約束,就使用 pattern
方法在 RouteServiceProvider
的 boot
方法中定義這些模式:
/** * 定義你的路由模型綁定, pattern 過濾器等。 * * @return void */ public function boot(){ Route::pattern('id', '[0-9]+'); parent::boot(); }
一旦定義好之后,便會自動應用這些規(guī)則到所有使用該參數(shù)名稱的路由上:
Route::get('user/{id}', function ($id) { // 只有在 id 為數(shù)字時才執(zhí)行。 });
編碼正斜杠字符
Laravel 路由組件允許除 /
之外的所有字符。你必須使用 where
條件正則表達式顯式地允許 /
成為占位符的一部分:
Route::get('search/{search}', function ($search) { return $search; })->where('search', '.*');
注意:編碼正斜杠字符僅在最后一個路由段中是支持的。
路由命名
路由命名可以方便地為指定路由生成 URL 或者重定向。通過在路由定義上鏈式調(diào)用 name
方法可以指定路由名稱:
Route::get('user/profile', function () { // })->name('profile');
你還可以指定控制器行為的路由名稱:
Route::get('user/profile', 'UserProfileController@show')->name('profile');
生成指定路由的 URL
為路由指定了名稱后,就可以使用全局輔助函數(shù) route
來生成鏈接或者重定向到該路由:
// 生成 URL... $url = route('profile'); // 生成重定向... return redirect()->route('profile');
如果是有定義參數(shù)的命名路由,可以把參數(shù)作為 route
函數(shù)的第二個參數(shù)傳入,指定的參數(shù)將會自動插入到 URL 中對應的位置:
Route::get('user/{id}/profile', function ($id) { // })->name('profile'); $url = route('profile', ['id' => 1]);
檢查當前路由
如果你想判斷當前請求是否指向了某個路由,你可以調(diào)用路由實例上的 named
方法。例如,你可以在路由中間件中檢查當前路由名稱:
/** * 處理一次請求。 * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next){ if ($request->route()->named('profile')) { // } return $next($request); }
路由組
路由組允許你在大量路由之間共享路由屬性,例如中間件或命名空間,而不需要為每個路由單獨定義這些屬性。共享屬性應該以數(shù)組的形式傳入 Route::group
方法的第一個參數(shù)中。
中間件
要給路由組中所有的路由分配中間件,可以在 group 之前調(diào)用 middleware
方法,中間件會依照它們在數(shù)組中列出的順序來運行:
Route::middleware(['first', 'second'])->group(function () { Route::get('/', function () { // // 使用 first 和 second 中間件 }); Route::get('user/profile', function () { // // 使用 first 和 second 中間件 }); });
命名空間
另一個常見用例是使用 namespace
方法將相同的 PHP 命名空間分配給路由組的中所有的控制器:
Route::namespace('Admin')->group(function () { // 在 "App\Http\Controllers\Admin" 命名空間下的控制器 });
請記住,默認情況下,RouteServiceProvider
會在命名空間組中引入你的路由文件,讓你不用指定完整的 App\Http\Controllers
命名空間前綴就能注冊控制器路由。因此,你只需要指定命名空間 App\Http\Controllers
之后的部分。
子域名路由
路由組也可以用來處理子域名。子域名可以像路由 URI 一樣被分配路由參數(shù),允許你獲取一部分子域名作為參數(shù)給路由或控制器使用??梢栽?group 之前調(diào)用 domain
方法來指定子域名:
Route::domain('{account}.myapp.com')->group(function () { Route::get('user/{id}', function ($account, $id) { // }); });
路由前綴
可以用 prefix
方法為路由組中給定的 URL 增加前綴。例如,你可以為組中所有路由的 URI 加上 admin 前綴:
Route::prefix('admin')->group(function () { Route::get('users', function () { // 匹配包含 "/admin/users" 的 URL }); });
路由名稱前綴
name 方法可以用來給路由組中的每個路由名稱添加一個給定的字符串。 例如,您可能希望以 「admin」為所有分組路由的名稱加前綴。 給定的字符串與指定的路由名稱前綴完全相同,因此我們將確保在前綴中提供尾部的 .
字符:
Route::name('admin.')->group(function () { Route::get('users', function () { // 指定路由名為 "admin.users"... })->name('users');});
路由模型綁定
當向路由或控制器行為注入模型 ID 時,就需要查詢這個 ID 對應的模型。Laravel 為路由模型綁定提供了一個直接自動將模型實例注入到路由中的方法。例如,你可以注入與給定 ID 匹配的整個 User
模型實例,而不是注入用戶的 ID。
隱式綁定
Laravel 會自動解析定義在路由或控制器行為中與類型提示的變量名匹配的路由段名稱的 Eloquent 模型。例如:
Route::get('api/users/{user}', function (App\User $user) { return $user->email; });
在這個例子中,由于 $user
變量被類型提示為 Eloquent 模型 App\User
,變量名稱又與 URI 中的 {user}
匹配,因此,Laravel 會自動注入與請求 URI 中傳入的 ID 匹配的用戶模型實例。如果在數(shù)據(jù)庫中找不到對應的模型實例,將會自動生成 404 異常。
自定義鍵名
如果你想要模型綁定在檢索給定的模型類時使用除 id
之外的數(shù)據(jù)庫字段,你可以在 Eloquent 模型上重寫 getRouteKeyName
方法:
/** * 獲取該模型的路由的自定義鍵名。 * * @return string */ public function getRouteKeyName(){ return 'slug'; }
顯式綁定
要注冊顯式綁定,使用路由器的 model
方法來為給定參數(shù)指定類。在 RouteServiceProvider
類中的 boot
方法內(nèi)定義這些顯式模型綁定:
public function boot(){ parent::boot(); Route::model('user', App\User::class); }
接著,定義一個包含 {user}
參數(shù)的路由:
Route::get('profile/{user}', function (App\User $user) { // });
因為我們已經(jīng)將所有 {user}
參數(shù)綁定至 App\User
模型,所以 User
實例將被注入該路由。例如,profile/1
的請求會注入數(shù)據(jù)庫中 ID 為 1 的 User
實例。
如果在數(shù)據(jù)庫中找不到匹配的模型實例,就會自動拋出一個 404 異常。
自定義邏輯解析
如果你想要使用自定義的解析邏輯,就使用 Route::bind
方法。傳遞到 bind
方法的 閉包
會接受 URI 中大括號對應的值,并且返回你想要在該路由中注入的類的實例:
/** * 啟動應用服務。 * * @return void */ public function boot(){ parent::boot(); Route::bind('user', function ($value) { return App\User::where('name', $value)->first() ?? abort(404); }); }
或者,您可以重寫 Eloquent 模型上的 resolveRouteBinding
方法。 此方法會接受 URI 中大括號對應的值,并且返回你想要在該路由中注入的類的實例:
/** * 檢索綁定值的模型。 * * @param mixed $value * @return \Illuminate\Database\Eloquent\Model|null */ public function resolveRouteBinding($value){ return $this->where('name', $value)->first() ?? abort(404); }
回退路由
使用 Route::fallback
方法, 你可以定義在沒有其他路由匹配傳入請求時執(zhí)行的路由。通常,未處理的請求會通過應用程序的異常處理程序自動呈現(xiàn) “404” 頁面。 但是,因為你可以在 routes/web.php
文件中定義 fallback
路由,web
中間件的所有中間件都將應用到路由中。 當然,你也可以根據(jù)需要向這條路由中添加額外的中間件:
Route::fallback(function () { // });
{note} 回退路由應始終是你應用程序注冊的最后一個路由。
訪問控制
Laravel 包含了一個 middleware 用于控制應用程序?qū)β酚傻脑L問。 如果想要使用, 請將 throttle
中間件分配給一個路由或者一個路由組。throttle
中間件會接收兩個參數(shù),這兩個參數(shù)決定了在給定的分鐘數(shù)內(nèi)可以進行的最大請求數(shù)。例如,讓我們指定一個經(jīng)過身份驗證并且用戶每分鐘訪問頻率不超過 60 次的路由組:
Route::middleware('auth:api', 'throttle:60,1')->group(function () { Route::get('/user', function () { // }); });
動態(tài)訪問控制
你可以根據(jù)已驗證的 User
模型的屬性,指定動態(tài)請求的最大值。例如,如果你的 User
模型包含 rate_limit
屬性,則可以將屬性名稱傳遞給 throttle
中間件,以便它用于計算最大請求數(shù):
Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () { Route::get('/user', function () { // }); });
表單方法偽造
HTML 表單不支持 PUT
、PATCH
或 DELETE
行為。所以當你要從 HTML 表單中調(diào)用定義了 PUT
、 PATCH
或 DELETE
行為的路由時,你將需要在表單中增加一個隱藏的 _method
輸入標簽。使用 _method
字段的值作為 HTTP 的請求方法:
<form action="/foo/bar" method="POST"> <input type="hidden" name="_method" value="PUT"> <input type="hidden" name="_token" value="{{ csrf_token() }}"> </form>
你也可以使用 @method
模板指令生成 _method
輸入:
<form action="/foo/bar" method="POST"> @method('PUT') @csrf </form>
訪問當前路由
你可以使用 Route facade 上的 current
、 currentRouteName
和 currentRouteAction
方法來訪問處理傳入請求的路由的信息:
$route = Route::current(); $name = Route::currentRouteName(); $action = Route::currentRouteAction();
如果你想知道所有可訪問的方法,可以查看 API 文檔,了解 Route facade 和 Route 實例 的基礎類。