路由
路由
建構基本的路由只需要一個URI 與一個
閉包 ,這裡提供了一個非常簡單優雅定義路由的方法:Route::get('foo', function () {
return 'Hello World';
});
預設路由檔案
所有的 Laravel 路由都在 routes
目錄中的路由檔案中定義,這些檔案都由框架自動載入。 routes/web.php
檔案用於定義 web
介面的路由。這裡面的路由都會被指派給 web
中間件群組,它提供了會話狀態和 CSRF 保護等功能。定義在 routes/api.php
中的路由都是無狀態的,並且被指派了 api
中間件群組。
大多數的應用程式構建,都是以在 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
方法註冊一個實現回應所有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
方法。這個方法可以快速的實作重定向,而不再需要去定義完整的路由或控制器:
Route::redirect('/here', '/there');
#Route::redirect
預設會回傳狀態碼302
。你可以透過第三個參數自訂回傳碼:
Route::redirect('/here', '/there', 301);
你也可以使用Route::permanentRedirect
方法來回傳301
狀態碼:
Route::permanentRedirect('/here', '/there');
視圖路由
如果你的路由只需要回傳一個視圖,可以使用 Route::view
方法。它和 redirect
一樣方便,不需要定義完整的路由或控制器。 view
方法有三個參數,其中第一個是必填參數,是包含視圖名稱的 URI 。第二個也是必填參數,是需要渲染的視圖名稱。第三個參數是可選參數,可以傳入一個數組,數組中的資料會傳遞給視圖:
Route::view('/welcome', 'welcome'); Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
路由參數
必填參數
當然,有時需要在路由中擷取一些URL 片段。例如,從URL 擷取使用者的ID,可以透過定義路由參數來執行此操作:
Route::get('user/{id}', function ($id) { return 'User '.$id; });
也可以根據需要在路由中定義多個參數:
Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) { // });
路由的參數通常都會被放在{}
內,且參數名稱只能為字母,同時路由參數不能包含-
符號,如果需要可以用底線(_
)代替。路由參數會依序依序注入路由回呼或控制器中,而不受回呼或控制器的參數名稱的影響。
可選擇參數
#有時,你可能需要指定一個路由參數,但你希望這個參數是可選的。你可以在參數後面加上?
標記來實現,但前提是要確保路由的對應變數有預設值
Route::get('user/{name?}', function ($name = null) { return $name; }); Route::get('user/{name?}', function ($name = 'John') { return $name; });
where 方法約束路由參數的格式。
where 方法接受參數名稱和定義參數應如何約束的正規表示式:
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]+']);全域限制如果你希望某個具體的路由參數都遵循同一個正規表示式的約束,就使用
pattern 方法在
RouteServiceProvider 的
boot 方法中定義這些模式:
/** * 定义你的路由模型绑定, pattern 过滤器等。 * * @return void */ public function boot(){ Route::pattern('id', '[0-9]+'); parent::boot(); }一旦定義好之後,就會自動套用這些規則到所有使用該參數名稱的路由上:
Route::get('user/{id}', function ($id) { // 只有在 id 为数字时才执行。 });#編碼正斜線字元Laravel 路由元件允許除
/ 之外的所有字元。你必須使用
where 條件正規表示式明確地允許
/ 成為佔位符的一部分:
Route::get('search/{search}', function ($search) { return $search; })->where('search', '.*');注意:編碼正斜線字元僅在最後一個路由段中是支援的。
路由命名
路由命名可以方便地為指定路由產生 URL 或重定向。透過在路由定義上鍊式呼叫 name
方法可以指定路由名稱:
Route::get('user/profile', function () { // })->name('profile');
你也可以指定控制器行為的路由名稱:
Route::get('user/profile', 'UserProfileController@show')->name('profile');
#產生指定路由的URL
為路由指定了名稱後,就可以使用全域輔助函數 route
來產生連結或重新導向到該路由:
// 生成 URL... $url = route('profile'); // 生成重定向... return redirect()->route('profile');
如果是有定義參數的命名路由,可以將參數當作 route
函數的第二個參數傳入,指定的參數將會自動插入URL 對應的位置:
Route::get('user/{id}/profile', function ($id) { // })->name('profile'); $url = route('profile', ['id' => 1]);
檢查目前路由
如果你想判斷目前請求是否指向了某個路由,你可以呼叫路由實例上的 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); }
#路由群組
#路由群組允許你在大量路由之間共用路由屬性,例如中間件或命名空間,而不需要為每個路由單獨定義這些屬性。共享屬性應該以陣列的形式傳入 Route::group
方法的第一個參數。
中間件
#要給路由群組中所有的路由分配中間件,可以在group 之前呼叫middleware
方法,中間件會依照它們在陣列中列出的順序來執行:
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 一樣被指派路由參數,讓你取得一部分子網域作為參數給路由或控制器使用。可以在group 之前呼叫domain
方法來指定子網域:
Route::domain('{account}.myapp.com')->group(function () { Route::get('user/{id}', function ($account, $id) { // }); });
路由前綴
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。
Route::get('api/users/{user}', function (App\User $user) { return $user->email; });在這個範例中,由於
$user 變數被型別提示為Eloquent 模型
App\User,變數名稱又與URI 中的
{user} 匹配,因此,Laravel 會自動注入與請求URI 中傳入的ID 匹配的使用者模型實例。如果在資料庫中找不到對應的模型實例,將會自動產生 404 個異常。
id 之外的資料庫字段,你可以在Eloquent 模型上重寫
getRouteKeyName 方法:
/** * 获取该模型的路由的自定义键名。 * * @return string */ public function getRouteKeyName(){ return 'slug'; }明確綁定要註冊明確綁定,使用路由器的
model 方法來為給定參數指定類別。在
RouteServiceProvider 類別中的
boot 方法內定義這些明確模型綁定:
public function boot(){ parent::boot(); Route::model('user', App\User::class); }接著,定義一個包含
{user} 參數的路由:
Route::get('profile/{user}', function (App\User $user) { // });因為我們已經將所有
{user} 參數綁定到
App\User 模型,所以
User 實例將會被注入該路由。例如,
profile/1 的請求會注入資料庫中 ID 為 1 的
User 實例。
自訂邏輯解析
如果你想要使用自訂的解析邏輯,就使用 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
方法, 你可以定義在沒有其他路由比對傳入要求時執行的路由。通常,未處理的請求會透過應用程式的異常處理程序自動呈現 “404” 頁面。但是,因為你可以在 routes/web.php
檔案中定義 fallback
路由,web
中間件的所有中間件都會套用到路由中。當然,你也可以根據需要在這條路由中添加額外的中間件:
Route::fallback(function () { // });
{note} 回退路由應始終是你應用程式註冊的最後一個路由。
存取控制
Laravel 包含了一個 middleware 用於控制應用程式對路由的存取。如果想要使用, 請將 throttle
中間件分配給一個路由或一個路由組。 throttle
中介軟體會接收兩個參數,這兩個參數決定了在給定的分鐘數內可以進行的最大請求數。例如,讓我們指定一個經過驗證且使用者每分鐘存取頻率不超過60 次的路由群組:
Route::middleware('auth:api', 'throttle:60,1')->group(function () { Route::get('/user', function () { // }); });
動態存取控制
你可以根據已驗證的User
模型的屬性,指定動態請求的最大值。例如,如果你的User
模型包含rate_limit
屬性,則可以將屬性名稱傳遞給throttle
中間件,以便它用於計算最大請求數:
Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () { Route::get('/user', function () { // }); });
表單方法偽造
HTML 表單不支援PUT
、PATCH
或DELETE
行為。所以當你要從HTML 表單中呼叫定義了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 實例 的基礎類別。