基本路由 (Basic Routing)
最基本的 Laravel 路由接受一個 URI 和一個 Closure,提供了一種非常簡單且富有表現力的方法來定義路由和行為,而無需複雜的路由設定檔:
use Illuminate\Support\Facades\Route;
Route::get('/greeting', function () {
return 'Hello World';
});
預設路由檔案 (The Default Route Files)
所有 Laravel 路由都在您的路由檔案中定義,這些檔案位於 routes 目錄中。這些檔案由 Laravel 使用應用程式 bootstrap/app.php 檔案中指定的設定自動載入。routes/web.php 檔案定義了用於 Web 介面的路由。這些路由被分配了 web Middleware 群組,該群組提供了 Session 狀態和 CSRF 保護等功能。
對於大多數應用程式,您將從在 routes/web.php 檔案中定義路由開始。可以透過在瀏覽器中輸入定義的路由 URL 來存取 routes/web.php 中定義的路由。例如,您可以透過在瀏覽器中導航到 http://example.com/user 來存取以下路由:
use App\Http\Controllers\UserController;
Route::get('/user', [UserController::class, 'index']);
API 路由 (Api Routes)
如果您的應用程式還將提供無狀態 API,您可以使用 install:api Artisan 指令啟用 API 路由:
php artisan install:api
install:api 指令會安裝 Laravel Sanctum,它提供了一個強大且簡單的 API Token 驗證 Guard,可用於驗證第三方 API 消費者、SPA 或行動應用程式。此外,install:api 指令會建立 routes/api.php 檔案:
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
routes/api.php 中的路由是無狀態的,並分配給 api Middleware 群組。此外,/api URI 前綴會自動應用於這些路由,因此您無需手動將其應用於檔案中的每個路由。您可以透過修改應用程式的 bootstrap/app.php 檔案來更改前綴:
->withRouting(
api: __DIR__.'/../routes/api.php',
apiPrefix: 'api/admin',
// ...
)
可用的 Router 方法 (Available Router Methods)
Router 允許您註冊響應任何 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('/', function () {
// ...
});
[!NOTE] 當定義多個共用相同 URI 的路由時,使用
get、post、put、patch、delete和options方法的路由應定義在使用any、match和redirect方法的路由之前。這確保了傳入的請求與正確的路由匹配。
Dependency Injection
您可以在路由的 Callback 簽名中對路由所需的任何依賴項進行型別提示 (Type-hint)。聲明的依賴項將由 Laravel Service Container 自動解析並注入到 Callback 中。例如,您可以對 Illuminate\Http\Request 類別進行型別提示,以便將當前 HTTP 請求自動注入到您的路由 Callback 中:
use Illuminate\Http\Request;
Route::get('/users', function (Request $request) {
// ...
});
CSRF 保護 (Csrf Protection)
請記住,任何指向 web 路由檔案中定義的 POST、PUT、PATCH 或 DELETE 路由的 HTML 表單都應包含 CSRF Token 欄位。否則,請求將被拒絕。您可以在 CSRF 文件 中閱讀有關 CSRF 保護的更多資訊:
<form method="POST" action="/profile">
@csrf
...
</form>
重新導向路由 (Redirect Routes)
如果您正在定義一個重新導向到另一個 URI 的路由,您可以使用 Route::redirect 方法。此方法提供了一個方便的捷徑,因此您不必為了執行簡單的重新導向而定義完整的路由或 Controller:
Route::redirect('/here', '/there');
預設情況下,Route::redirect 返回 302 狀態碼。您可以使用可選的第三個參數自訂狀態碼:
Route::redirect('/here', '/there', 301);
或者,您可以使用 Route::permanentRedirect 方法返回 301 狀態碼:
Route::permanentRedirect('/here', '/there');
[!WARNING] 在重新導向路由中使用路由參數時,以下參數由 Laravel 保留,不能使用:
destination和status。
View 路由 (View Routes)
如果您的路由只需要返回一個 View,您可以使用 Route::view 方法。就像 redirect 方法一樣,此方法提供了一個簡單的捷徑,因此您不必定義完整的路由或 Controller。view 方法接受 URI 作為其第一個參數,View 名稱作為其第二個參數。此外,您可以提供一個資料陣列作為可選的第三個參數傳遞給 View:
Route::view('/welcome', 'welcome');
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
[!WARNING] 在 View 路由中使用路由參數時,以下參數由 Laravel 保留,不能使用:
view、data、status和headers。
列出您的路由 (Listing Your Routes)
route:list Artisan 指令可以輕鬆提供應用程式定義的所有路由的概覽:
php artisan route:list
預設情況下,分配給每個路由的路由 Middleware 不會顯示在 route:list 輸出中;但是,您可以透過在指令中新增 -v 選項來指示 Laravel 顯示路由 Middleware 和 Middleware 群組名稱:
php artisan route:list -v
# Expand middleware groups...
php artisan route:list -vv
您還可以指示 Laravel 僅顯示以給定 URI 開頭的路由:
php artisan route:list --path=api
此外,您可以在執行 route:list 指令時提供 --except-vendor 選項,指示 Laravel 隱藏任何由第三方套件定義的路由:
php artisan route:list --except-vendor
同樣,您也可以在執行 route:list 指令時提供 --only-vendor 選項,指示 Laravel 僅顯示由第三方套件定義的路由:
php artisan route:list --only-vendor
路由自訂 (Routing Customization)
預設情況下,您的應用程式的路由由 bootstrap/app.php 檔案設定和載入:
<?php
use Illuminate\Foundation\Application;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)->create();
但是,有時您可能希望定義一個全新的檔案來包含應用程式路由的子集。為此,您可以向 withRouting 方法提供一個 then Closure。在此 Closure 中,您可以註冊應用程式所需的任何其他路由:
use Illuminate\Support\Facades\Route;
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
then: function () {
Route::middleware('api')
->prefix('webhooks')
->name('webhooks.')
->group(base_path('routes/webhooks.php'));
},
)
或者,您甚至可以透過向 withRouting 方法提供 using Closure 來完全控制路由註冊。傳遞此參數時,框架將不會註冊任何 HTTP 路由,您負責手動註冊所有路由:
use Illuminate\Support\Facades\Route;
->withRouting(
commands: __DIR__.'/../routes/console.php',
using: function () {
Route::middleware('api')
->prefix('api')
->group(base_path('routes/api.php'));
Route::middleware('web')
->group(base_path('routes/web.php'));
},
)
路由參數 (Route Parameters)
必要參數 (Required Parameters)
有時您需要在路由中擷取 URI 的片段。例如,您可能需要從 URL 中擷取使用者的 ID。您可以透過定義路由參數來實現:
Route::get('/user/{'{id}'}', function (string $id) {
return 'User '.$id;
});
您可以根據路由需要定義任意數量的路由參數:
Route::get('/posts/{'{post}'}/comments/{'{comment}'}', function (string $postId, string $commentId) {
// ...
});
路由參數總是包含在 {} 大括號內,並且應由字母字元組成。底線 (_) 在路由參數名稱中也是可以接受的。路由參數根據其順序注入到路由 Callback / Controller 中 - 路由 Callback / Controller 參數的名稱並不重要。
參數與 Dependency Injection (Parameters And Dependency Injection)
如果您的路由具有您希望 Laravel Service Container 自動注入到路由 Callback 中的依賴項,您應該在依賴項之後列出您的路由參數:
use Illuminate\Http\Request;
Route::get('/user/{'{id}'}', function (Request $request, string $id) {
return 'User '.$id;
});
可選參數 (Parameters Optional Parameters)
偶爾您可能需要指定一個可能並不總是存在於 URI 中的路由參數。您可以透過在參數名稱後加上 ? 標記來實現。確保給路由的相應變數一個預設值:
Route::get('/user/{name?}', function (?string $name = null) {
return $name;
});
Route::get('/user/{name?}', function (?string $name = 'John') {
return $name;
});
正規表示式約束 (Parameters Regular Expression Constraints)
您可以使用路由實例上的 where 方法約束路由參數的格式。where 方法接受參數名稱和定義參數應如何約束的正規表示式:
Route::get('/user/{'{name}'}', function (string $name) {
// ...
})->where('name', '[A-Za-z]+');
Route::get('/user/{'{id}'}', function (string $id) {
// ...
})->where('id', '[0-9]+');
Route::get('/user/{'{id}'}/{'{name}'}', function (string $id, string $name) {
// ...
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
為了方便起見,一些常用的正規表示式模式具有 Helper 方法,允許您快速將模式約束新增到您的路由中:
Route::get('/user/{'{id}'}/{'{name}'}', function (string $id, string $name) {
// ...
})->whereNumber('id')->whereAlpha('name');
Route::get('/user/{'{name}'}', function (string $name) {
// ...
})->whereAlphaNumeric('name');
Route::get('/user/{'{id}'}', function (string $id) {
// ...
})->whereUuid('id');
Route::get('/user/{'{id}'}', function (string $id) {
// ...
})->whereUlid('id');
Route::get('/category/{'{category}'}', function (string $category) {
// ...
})->whereIn('category', ['movie', 'song', 'painting']);
Route::get('/category/{'{category}'}', function (string $category) {
// ...
})->whereIn('category', CategoryEnum::cases());
如果傳入的請求與路由模式約束不匹配,將返回 404 HTTP 回應。
全域約束 (Parameters Global Constraints)
如果您希望路由參數始終受給定正規表示式的約束,您可以使用 pattern 方法。您應該在應用程式的 App\Providers\AppServiceProvider 類別的 boot 方法中定義這些模式:
use Illuminate\Support\Facades\Route;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Route::pattern('id', '[0-9]+');
}
一旦定義了模式,它將自動應用於所有使用該參數名稱的路由:
Route::get('/user/{'{id}'}', function (string $id) {
// Only executed if {'{id}'} is numeric...
});
編碼的正斜線 (Parameters Encoded Forward Slashes)
Laravel 路由元件允許除 / 之外的所有字元出現在路由參數值中。您必須使用 where 條件正規表示式明確允許 / 成為預留位置的一部分:
Route::get('/search/{'{search}'}', function (string $search) {
return $search;
})->where('search', '.*');
[!WARNING] 編碼的正斜線僅在最後一個路由片段中受支援。
命名路由 (Named Routes)
命名路由允許方便地為特定路由生成 URL 或重新導向。您可以透過將 name 方法鏈接到路由定義來為路由指定名稱:
Route::get('/user/profile', function () {
// ...
})->name('profile');
您還可以為 Controller Action 指定路由名稱:
Route::get(
'/user/profile',
[UserProfileController::class, 'show']
)->name('profile');
[!WARNING] 路由名稱應始終是唯一的。
生成命名路由的 URL (Generating Urls To Named Routes)
一旦您為給定路由分配了名稱,您就可以在透過 Laravel 的 route 和 redirect Helper 函式生成 URL 或重新導向時使用該路由的名稱:
// Generating URLs...
$url = route('profile');
// Generating Redirects...
return redirect()->route('profile');
return to_route('profile');
如果命名路由定義了參數,您可以將參數作為第二個參數傳遞給 route 函式。給定的參數將自動插入到生成的 URL 中的正確位置:
Route::get('/user/{'{id}'}/profile', function (string $id) {
// ...
})->name('profile');
$url = route('profile', ['id' => 1]);
如果您在陣列中傳遞其他參數,這些鍵/值對將自動新增到生成的 URL 的查詢字串中:
Route::get('/user/{'{id}'}/profile', function (string $id) {
// ...
})->name('profile');
$url = route('profile', ['id' => 1, 'photos' => 'yes']);
// http://example.com/user/1/profile?photos=yes
[!NOTE] 有時,您可能希望為 URL 參數指定請求範圍的預設值,例如當前語言環境。為此,您可以使用 URL::defaults 方法。
檢查當前路由 (Inspecting The Current Route)
如果您想確定當前請求是否路由到給定的命名路由,您可以使用 Route 實例上的 named 方法。例如,您可以從路由 Middleware 檢查當前路由名稱:
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($request->route()->named('profile')) {
// ...
}
return $next($request);
}
路由群組 (Route Groups)
路由群組允許您共用路由屬性,例如 Middleware,跨越大量路由,而無需在每個單獨的路由上定義這些屬性。
巢狀群組嘗試智慧地將屬性與其父群組「合併」。Middleware 和 where 條件被合併,而名稱和前綴被附加。命名空間分隔符和 URI 前綴中的斜線會在適當的地方自動新增。
Middleware
要將 Middleware 分配給群組內的所有路由,您可以在定義群組之前使用 middleware 方法。Middleware 按照它們在陣列中列出的順序執行:
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// Uses first & second middleware...
});
Route::get('/user/profile', function () {
// Uses first & second middleware...
});
});
Controllers
如果一組路由都使用相同的 Controller,您可以使用 controller 方法為群組內的所有路由定義通用的 Controller。然後,在定義路由時,您只需要提供它們呼叫的 Controller 方法:
use App\Http\Controllers\OrderController;
Route::controller(OrderController::class)->group(function () {
Route::get('/orders/{'{id}'}', 'show');
Route::post('/orders', 'store');
});
子網域路由 (Route Group Subdomain Routing)
路由群組也可用於處理子網域路由。子網域可以像路由 URI 一樣分配路由參數,允許您擷取子網域的一部分以在您的路由或 Controller 中使用。可以在定義群組之前呼叫 domain 方法來指定子網域:
Route::domain('{'{account}'}.example.com')->group(function () {
Route::get('/user/{'{id}'}', function (string $account, string $id) {
// ...
});
});
[!WARNING] 為了確保您的子網域路由可存取,您應該在註冊根網域路由之前註冊子網域路由。這將防止根網域路由覆蓋具有相同 URI 路徑的子網域路由。
路由前綴 (Route Group Prefixes)
prefix 方法可用於為群組中的每個路由加上給定的 URI 前綴。例如,您可能希望為群組內的所有路由 URI 加上 admin 前綴:
Route::prefix('admin')->group(function () {
Route::get('/users', function () {
// Matches The "/admin/users" URL
});
});
路由名稱前綴 (Route Group Name Prefixes)
name 方法可用於為群組中的每個路由名稱加上給定的字串前綴。例如,您可能希望為群組中所有路由的名稱加上 admin 前綴。給定的字串完全按照指定的方式加到路由名稱前,因此我們將確保在前綴中提供尾隨的 . 字元:
Route::name('admin.')->group(function () {
Route::get('/users', function () {
// Route assigned name "admin.users"...
})->name('users');
});
路由 Model 綁定 (Route Model Binding)
當將 Model ID 注入到路由或 Controller Action 時,您通常會查詢資料庫以檢索與該 ID 對應的 Model。Laravel 路由 Model 綁定提供了一種方便的方法,可以自動將 Model 實例直接注入到您的路由中。例如,您可以注入與給定 ID 匹配的整個 User Model 實例,而不是注入使用者的 ID。
隱式綁定 (Implicit Binding)
Laravel 自動解析在路由或 Controller Action 中定義的 Eloquent Model,其型別提示的變數名稱與路由片段名稱匹配。例如:
use App\Models\User;
Route::get('/users/{'{user}'}', function (User $user) {
return $user->email;
});
由於 $user 變數被型別提示為 App\Models\User Eloquent Model,並且變數名稱與 {user} URI 片段匹配,Laravel 將自動注入具有與請求 URI 中的相應值匹配的 ID 的 Model 實例。如果在資料庫中找不到匹配的 Model 實例,將自動生成 404 HTTP 回應。
當然,在使用 Controller 方法時也可以進行隱式綁定。再次注意,{user} URI 片段與 Controller 中包含 App\Models\User 型別提示的 $user 變數匹配:
use App\Http\Controllers\UserController;
use App\Models\User;
// Route definition...
Route::get('/users/{'{user}'}', [UserController::class, 'show']);
// Controller method definition...
public function show(User $user)
{
return view('user.profile', ['user' => $user]);
}
軟刪除的 Models (Implicit Soft Deleted Models)
通常,隱式 Model 綁定不會檢索已 軟刪除 的 Model。但是,您可以透過將 withTrashed 方法鏈接到您的路由定義來指示隱式綁定檢索這些 Model:
use App\Models\User;
Route::get('/users/{'{user}'}', function (User $user) {
return $user->email;
})->withTrashed();
自訂 Key (Customizing The Default Key Name)
有時您可能希望使用 id 以外的欄位解析 Eloquent Model。為此,您可以在路由參數定義中指定欄位:
use App\Models\Post;
Route::get('/posts/{post:slug}', function (Post $post) {
return $post;
});
如果您希望 Model 綁定在檢索給定 Model 類別時始終使用 id 以外的資料庫欄位,您可以覆蓋 Eloquent Model 上的 getRouteKeyName 方法:
/**
* Get the route key for the model.
*/
public function getRouteKeyName(): string
{
return 'slug';
}
自訂 Keys 和 Scoping (Implicit Model Binding Scoping)
當在單個路由定義中隱式綁定多個 Eloquent Model 時,您可能希望對第二個 Eloquent Model 進行範圍限定,使其必須是前一個 Eloquent Model 的子項。例如,考慮這個為特定使用者透過 slug 檢索部落格文章的路由定義:
use App\Models\Post;
use App\Models\User;
Route::get('/users/{'{user}'}/posts/{post:slug}', function (User $user, Post $post) {
return $post;
});
當使用自訂鍵控隱式綁定作為巢狀路由參數時,Laravel 將自動限定查詢範圍,使用慣例猜測父項上的關聯名稱,透過其父項檢索巢狀 Model。在這種情況下,將假設 User Model 有一個名為 posts(路由參數名稱的複數形式)的關聯,可用於檢索 Post Model。
如果您願意,即使未提供自訂鍵,您也可以指示 Laravel 限定「子」綁定的範圍。為此,您可以在定義路由時呼叫 scopeBindings 方法:
use App\Models\Post;
use App\Models\User;
Route::get('/users/{'{user}'}/posts/{'{post}'}', function (User $user, Post $post) {
return $post;
})->scopeBindings();
或者,您可以指示整個路由定義群組使用限定範圍的綁定:
Route::scopeBindings()->group(function () {
Route::get('/users/{'{user}'}/posts/{'{post}'}', function (User $user, Post $post) {
return $post;
});
});
同樣,您可以透過呼叫 withoutScopedBindings 方法明確指示 Laravel 不限定綁定範圍:
Route::get('/users/{'{user}'}/posts/{post:slug}', function (User $user, Post $post) {
return $post;
})->withoutScopedBindings();
自訂缺失 Model 行為 (Customizing Missing Model Behavior)
通常,如果找不到隱式綁定的 Model,將生成 404 HTTP 回應。但是,您可以透過在定義路由時呼叫 missing 方法來自訂此行為。missing 方法接受一個 Closure,如果找不到隱式綁定的 Model,將呼叫該 Closure:
use App\Http\Controllers\LocationsController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
Route::get('/locations/{location:slug}', [LocationsController::class, 'show'])
->name('locations.view')
->missing(function (Request $request) {
return Redirect::route('locations.index');
});
隱式 Enum 綁定 (Implicit Enum Binding)
PHP 8.1 引入了對 Enums 的支援。為了補充此功能,Laravel 允許您在路由定義上對 字串支援的 Enum 進行型別提示,並且僅當該路由片段對應於有效的 Enum 值時,Laravel 才會呼叫該路由。否則,將自動返回 404 HTTP 回應。例如,給定以下 Enum:
<?php
namespace App\Enums;
enum Category: string
{
case Fruits = 'fruits';
case People = 'people';
}
您可以定義一個僅當 {category} 路由片段為 fruits 或 people 時才會被呼叫的路由。否則,Laravel 將返回 404 HTTP 回應:
use App\Enums\Category;
use Illuminate\Support\Facades\Route;
Route::get('/categories/{'{category}'}', function (Category $category) {
return $category->value;
});
顯式綁定 (Explicit Binding)
您不需要使用 Laravel 的隱式、基於慣例的 Model 解析來使用 Model 綁定。您還可以顯式定義路由參數如何對應於 Model。要註冊顯式綁定,請使用 Router 的 model 方法為給定參數指定類別。您應該在 AppServiceProvider 類別的 boot 方法開頭定義顯式 Model 綁定:
use App\Models\User;
use Illuminate\Support\Facades\Route;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Route::model('user', User::class);
}
接下來,定義一個包含 {user} 參數的路由:
use App\Models\User;
Route::get('/users/{'{user}'}', function (User $user) {
// ...
});
由於我們已將所有 {user} 參數綁定到 App\Models\User Model,因此該類別的實例將被注入到路由中。因此,例如,對 users/1 的請求將注入資料庫中 ID 為 1 的 User 實例。
如果在資料庫中找不到匹配的 Model 實例,將自動生成 404 HTTP 回應。
自訂解析邏輯 (Customizing The Resolution Logic)
如果您希望定義自己的 Model 綁定解析邏輯,可以使用 Route::bind 方法。傳遞給 bind 方法的 Closure 將接收 URI 片段的值,並應返回應注入到路由中的類別實例。同樣,此自訂應在應用程式的 AppServiceProvider 的 boot 方法中進行:
use App\Models\User;
use Illuminate\Support\Facades\Route;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Route::bind('user', function (string $value) {
return User::where('name', $value)->firstOrFail();
});
}
或者,您可以覆蓋 Eloquent Model 上的 resolveRouteBinding 方法。此方法將接收 URI 片段的值,並應返回應注入到路由中的類別實例:
/**
* Retrieve the model for a bound value.
*
* @param mixed $value
* @param string|null $field
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function resolveRouteBinding($value, $field = null)
{
return $this->where('name', $value)->firstOrFail();
}
如果路由正在使用 隱式綁定範圍限定,則將使用 resolveChildRouteBinding 方法來解析父 Model 的子綁定:
/**
* Retrieve the child model for a bound value.
*
* @param string $childType
* @param mixed $value
* @param string|null $field
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function resolveChildRouteBinding($childType, $value, $field)
{
return parent::resolveChildRouteBinding($childType, $value, $field);
}
Fallback 路由 (Fallback Routes)
使用 Route::fallback 方法,您可以定義一個當沒有其他路由匹配傳入請求時將執行的路由。通常,未處理的請求將透過應用程式的異常處理常式自動呈現「404」頁面。但是,由於您通常會在 routes/web.php 檔案中定義 fallback 路由,因此 web Middleware 群組中的所有 Middleware 都將應用於該路由。您可以根據需要隨意向此路由新增其他 Middleware:
Route::fallback(function () {
// ...
});
限流 (Rate Limiting)
定義 Rate Limiters (Defining Rate Limiters)
Laravel 包含強大且可自訂的限流服務,您可以使用它們來限制給定路由或路由群組的流量。首先,您應該定義滿足應用程式需求的 Rate Limiter 設定。
Rate Limiters 可以在應用程式的 App\Providers\AppServiceProvider 類別的 boot 方法中定義:
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});
}
Rate Limiters 是使用 RateLimiter Facade 的 for 方法定義的。for 方法接受 Rate Limiter 名稱和一個 Closure,該 Closure 返回應應用於分配給 Rate Limiter 的路由的限制設定。限制設定是 Illuminate\Cache\RateLimiting\Limit 類別的實例。此類別包含有用的「建構器」方法,以便您可以快速定義限制。Rate Limiter 名稱可以是您希望的任何字串:
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
RateLimiter::for('global', function (Request $request) {
return Limit::perMinute(1000);
});
}
如果傳入請求超過指定的速率限制,Laravel 將自動返回帶有 429 HTTP 狀態碼的回應。如果您想定義自己的應由速率限制返回的回應,可以使用 response 方法:
RateLimiter::for('global', function (Request $request) {
return Limit::perMinute(1000)->response(function (Request $request, array $headers) {
return response('Custom response...', 429, $headers);
});
});
由於 Rate Limiter Callback 接收傳入的 HTTP 請求實例,因此您可以根據傳入的請求或經過驗證的使用者動態建構適當的速率限制:
RateLimiter::for('uploads', function (Request $request) {
return $request->user()->vipCustomer()
? Limit::none()
: Limit::perHour(10);
});
分段速率限制 (Segmenting Rate Limits)
有時您可能希望按某個任意值對速率限制進行分段。例如,您可能希望允許使用者每個 IP 位址每分鐘存取給定路由 100 次。為此,您可以在建構速率限制時使用 by 方法:
RateLimiter::for('uploads', function (Request $request) {
return $request->user()->vipCustomer()
? Limit::none()
: Limit::perMinute(100)->by($request->ip());
});
為了使用另一個範例說明此功能,我們可以將路由存取限制為每個經過驗證的使用者 ID 每分鐘 100 次,或對於訪客每個 IP 位址每分鐘 10 次:
RateLimiter::for('uploads', function (Request $request) {
return $request->user()
? Limit::perMinute(100)->by($request->user()->id)
: Limit::perMinute(10)->by($request->ip());
});
多重速率限制 (Multiple Rate Limits)
如果需要,您可以為給定的 Rate Limiter 設定返回速率限制陣列。將根據它們在陣列中的放置順序評估路由的每個速率限制:
RateLimiter::for('login', function (Request $request) {
return [
Limit::perMinute(500),
Limit::perMinute(3)->by($request->input('email')),
];
});
如果您要分配由相同的 by 值分段的多個速率限制,則應確保每個 by 值都是唯一的。實現此目的的最簡單方法是為 by 方法提供的值加上前綴:
RateLimiter::for('uploads', function (Request $request) {
return [
Limit::perMinute(10)->by('minute:'.$request->user()->id),
Limit::perDay(1000)->by('day:'.$request->user()->id),
];
});
基於回應的限流 (Response Base Rate Limiting)
除了限制傳入請求的速率之外,Laravel 還允許您使用 after 方法根據回應限制速率。當您只想將某些回應計入速率限制(例如驗證錯誤、404 回應或其他特定 HTTP 狀態碼)時,這很有用。
after 方法接受一個 Closure,該 Closure 接收回應,如果應將回應計入速率限制,則應返回 true,如果應忽略它,則返回 false。這對於透過限制連續的 404 回應來防止列舉攻擊,或允許使用者重試驗證失敗的請求而不會在僅應限制成功操作的端點上耗盡其速率限制特別有用:
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Symfony\Component\HttpFoundation\Response;
RateLimiter::for('resource-not-found', function (Request $request) {
return Limit::perMinute(10)
->by($request->user()?->id ?: $request->ip())
->after(function (Response $response) {
// Only count 404 responses toward the rate limit to prevent enumeration...
return $response->status() === 404;
});
});
將 Rate Limiters 附加到路由 (Attaching Rate Limiters To Routes)
可以使用 throttle Middleware 將 Rate Limiters 附加到路由或路由群組。throttle Middleware 接受您希望分配給路由的 Rate Limiter 名稱:
Route::middleware(['throttle:uploads'])->group(function () {
Route::post('/audio', function () {
// ...
});
Route::post('/video', function () {
// ...
});
});
使用 Redis 進行限流 (Throttling With Redis)
預設情況下,throttle Middleware 映射到 Illuminate\Routing\Middleware\ThrottleRequests 類別。但是,如果您使用 Redis 作為應用程式的快取驅動程式,您可能希望指示 Laravel 使用 Redis 來管理限流。為此,您應該在應用程式的 bootstrap/app.php 檔案中使用 throttleWithRedis 方法。此方法將 throttle Middleware 映射到 Illuminate\Routing\Middleware\ThrottleRequestsWithRedis Middleware 類別:
->withMiddleware(function (Middleware $middleware): void {
$middleware->throttleWithRedis();
// ...
})
表單方法偽造 (Form Method Spoofing)
HTML 表單不支援 PUT、PATCH 或 DELETE 動作。因此,當定義從 HTML 表單呼叫的 PUT、PATCH 或 DELETE 路由時,您需要在表單中新增一個隱藏的 _method 欄位。隨 _method 欄位發送的值將用作 HTTP 請求方法:
<form action="/example" method="POST">
<input type="hidden" name="_method" value="PUT">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
為了方便起見,您可以使用 @method Blade 指令 生成 _method 輸入欄位:
<form action="/example" method="POST">
@method('PUT')
@csrf
</form>
存取當前路由 (Accessing The Current Route)
您可以使用 Route Facade 上的 current、currentRouteName 和 currentRouteAction 方法來存取有關處理傳入請求的路由的資訊:
use Illuminate\Support\Facades\Route;
$route = Route::current(); // Illuminate\Routing\Route
$name = Route::currentRouteName(); // string
$action = Route::currentRouteAction(); // string
您可以參考 Route Facade 的底層類別 和 Route 實例 的 API 文件,以查看 Router 和 Route 類別上可用的所有方法。
跨來源資源共用 (CORS)
Laravel 可以使用您設定的值自動響應 CORS OPTIONS HTTP 請求。OPTIONS 請求將由 HandleCors Middleware 自動處理,該 Middleware 自動包含在應用程式的全域 Middleware 堆疊中。
有時,您可能需要自訂應用程式的 CORS 設定值。您可以透過使用 config:publish Artisan 指令發布 cors 設定檔來實現:
php artisan config:publish cors
此指令將在您的應用程式的 config 目錄中放置一個 cors.php 設定檔。
[!NOTE] 有關 CORS 和 CORS 標頭的更多資訊,請參閱 關於 CORS 的 MDN Web 文件。
路由快取 (Route Caching)
將應用程式部署到生產環境時,您應該利用 Laravel 的路由快取。使用路由快取將大大減少註冊應用程式所有路由所需的時間。要生成路由快取,請執行 route:cache Artisan 指令:
php artisan route:cache
執行此指令後,您的快取路由檔案將在每個請求上載入。請記住,如果您新增任何新路由,則需要生成新的路由快取。因此,您應該只在專案部署期間執行 route:cache 指令。
您可以使用 route:clear 指令清除路由快取:
php artisan route:clear