路由
基礎路由
最基本的 Laravel 路由僅接受一個 URI 和一個閉包,提供了一種非常簡單且直觀的方法來定義路由和行為,而無需複雜的路由配置檔案。
1use Illuminate\Support\Facades\Route;2 3Route::get('/greeting', function () {4 return 'Hello World';5});
預設路由檔案
所有的 Laravel 路由都在 routes 目錄下的路由檔案中定義。這些檔案由 Laravel 使用應用程式 bootstrap/app.php 檔案中指定的配置自動載入。routes/web.php 檔案用於定義 Web 介面的路由。這些路由會被分配到 web 中介軟體組,該組提供了諸如會話狀態和 CSRF 保護等功能。
對於大多數應用程式,您可以從在 routes/web.php 檔案中定義路由開始。在 routes/web.php 中定義的路由可以透過在瀏覽器中輸入定義的 URL 來訪問。例如,您可以透過在瀏覽器中導航至 http://example.com/user 來訪問以下路由。
1use App\Http\Controllers\UserController;2 3Route::get('/user', [UserController::class, 'index']);
API 路由
如果您的應用程式還將提供無狀態 API,您可以使用 install:api Artisan 命令啟用 API 路由。
1php artisan install:api
install:api 命令會安裝 Laravel Sanctum,它提供了一種強大且簡單的 API 令牌身份驗證守衛,可用於驗證第三方 API 使用者、SPA 或移動應用程式。此外,install:api 命令還會建立 routes/api.php 檔案。
1Route::get('/user', function (Request $request) {2 return $request->user();3})->middleware('auth:sanctum');
當然,您可以隨意在需要公開訪問的路由上省略 auth:sanctum 中介軟體。
routes/api.php 中的路由是無狀態的,並被分配給 api 中介軟體組。此外,/api URI 字首會自動應用於這些路由,因此您無需手動為檔案中的每個路由新增字首。您可以透過修改應用程式的 bootstrap/app.php 檔案來更改此字首。
1->withRouting(2 api: __DIR__.'/../routes/api.php',3 apiPrefix: 'api/admin',4 // ...5)
可用的路由器方法
路由器允許您註冊響應任何 HTTP 動詞的路由。
1Route::get($uri, $callback);2Route::post($uri, $callback);3Route::put($uri, $callback);4Route::patch($uri, $callback);5Route::delete($uri, $callback);6Route::options($uri, $callback);
有時您可能需要註冊一個響應多種 HTTP 動詞的路由。您可以使用 match 方法來實現。或者,您甚至可以使用 any 方法註冊一個響應所有 HTTP 動詞的路由。
1Route::match(['get', 'post'], '/', function () {2 // ...3});4 5Route::any('/', function () {6 // ...7});
在定義多個共享相同 URI 的路由時,使用 get、post、put、patch、delete 和 options 方法的路由應定義在使用 any、match 和 redirect 方法的路由之前。這可以確保傳入的請求與正確的路由匹配。
依賴注入
您可以在路由的回撥簽名中對路由所需的任何依賴進行型別提示。宣告的依賴項將由 Laravel 服務容器 自動解析並注入到回撥中。例如,您可以對 Illuminate\Http\Request 類進行型別提示,以將當前的 HTTP 請求自動注入到您的路由回撥中。
1use Illuminate\Http\Request;2 3Route::get('/users', function (Request $request) {4 // ...5});
CSRF 保護
請記住,在 web 路由檔案中定義的指向 POST、PUT、PATCH 或 DELETE 路由的任何 HTML 表單都應包含 CSRF 令牌欄位。否則,請求將被拒絕。您可以在 CSRF 文件 中閱讀有關 CSRF 保護的更多資訊。
1<form method="POST" action="/profile">2 @csrf3 ...4</form>
重定向路由
如果您定義的路由需要重定向到另一個 URI,可以使用 Route::redirect 方法。此方法提供了一個便捷的快捷方式,因此您無需為了簡單的重定向而定義完整的路由或控制器。
1Route::redirect('/here', '/there');
預設情況下,Route::redirect 返回 302 狀態碼。您可以使用可選的第三個引數自定義狀態碼。
1Route::redirect('/here', '/there', 301);
或者,您可以使用 Route::permanentRedirect 方法返回 301 狀態碼。
1Route::permanentRedirect('/here', '/there');
在重定向路由中使用路由引數時,以下引數被 Laravel 保留,不能使用:destination 和 status。
檢視路由
如果您的路由只需要返回一個 檢視,可以使用 Route::view 方法。與 redirect 方法一樣,此方法提供了一個簡單的快捷方式,無需定義完整的路由或控制器。view 方法接受 URI 作為第一個引數,檢視名稱作為第二個引數。此外,您可以提供一個數據陣列作為可選的第三個引數傳遞給檢視。
1Route::view('/welcome', 'welcome');2 3Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
在檢視路由中使用路由引數時,以下引數被 Laravel 保留,不能使用:view、data、status 和 headers。
檢視路由列表
route:list Artisan 命令可以輕鬆提供應用程式定義的所有路由的概覽。
1php artisan route:list
預設情況下,分配給每個路由的路由中介軟體不會顯示在 route:list 的輸出中;但是,您可以透過在命令中新增 -v 選項,指示 Laravel 顯示路由中介軟體和中介軟體組名稱。
1php artisan route:list -v2 3# Expand middleware groups...4php artisan route:list -vv
您還可以指示 Laravel 僅顯示以特定 URI 開頭的路由。
1php artisan route:list --path=api
此外,您可以在執行 route:list 命令時提供 --except-vendor 選項,以指示 Laravel 隱藏所有由第三方包定義的路由。
1php artisan route:list --except-vendor
同樣,您也可以在執行 route:list 命令時提供 --only-vendor 選項,以指示 Laravel 僅顯示由第三方包定義的路由。
1php artisan route:list --only-vendor
路由自定義
預設情況下,您的應用程式路由由 bootstrap/app.php 檔案配置和載入。
1<?php 2 3use Illuminate\Foundation\Application; 4 5return Application::configure(basePath: dirname(__DIR__)) 6 ->withRouting( 7 web: __DIR__.'/../routes/web.php', 8 commands: __DIR__.'/../routes/console.php', 9 health: '/up',10 )->create();
然而,有時您可能希望定義一個全新的檔案來包含應用程式路由的子集。為此,您可以向 withRouting 方法提供一個 then 閉包。在此閉包內,您可以註冊應用程式所需的任何額外路由。
1use Illuminate\Support\Facades\Route; 2 3->withRouting( 4 web: __DIR__.'/../routes/web.php', 5 commands: __DIR__.'/../routes/console.php', 6 health: '/up', 7 then: function () { 8 Route::middleware('api') 9 ->prefix('webhooks')10 ->name('webhooks.')11 ->group(base_path('routes/webhooks.php'));12 },13)
或者,您甚至可以透過向 withRouting 方法提供 using 閉包來完全控制路由註冊。當傳遞此引數時,框架不會註冊任何 HTTP 路由,您需要負責手動註冊所有路由。
1use Illuminate\Support\Facades\Route; 2 3->withRouting( 4 commands: __DIR__.'/../routes/console.php', 5 using: function () { 6 Route::middleware('api') 7 ->prefix('api') 8 ->group(base_path('routes/api.php')); 9 10 Route::middleware('web')11 ->group(base_path('routes/web.php'));12 },13)
路由引數
必填引數
有時您需要在路由中捕獲 URI 的片段。例如,您可能需要從 URL 中捕獲使用者的 ID。您可以透過定義路由引數來實現。
1Route::get('/user/{id}', function (string $id) {2 return 'User '.$id;3});
您可以根據需要定義任意數量的路由引數。
1Route::get('/posts/{post}/comments/{comment}', function (string $postId, string $commentId) {2 // ...3});
路由引數總是被包裹在 {} 花括號內,並且應該由字母字元組成。下劃線 (_) 在路由引數名稱中也是允許的。路由引數根據順序被注入到路由回撥/控制器中——路由回撥/控制器引數的名稱並不重要。
引數與依賴注入
如果您的路由有依賴項,並且希望 Laravel 服務容器自動將其注入到路由回撥中,則應將路由引數放在依賴項之後。
1use Illuminate\Http\Request;2 3Route::get('/user/{id}', function (Request $request, string $id) {4 return 'User '.$id;5});
可選引數
有時您可能需要指定一個 URI 中並不總是存在的路由引數。您可以透過在引數名稱後加一個 ? 來實現。請確保為路由的相應變數設定預設值。
1Route::get('/user/{name?}', function (?string $name = null) {2 return $name;3});4 5Route::get('/user/{name?}', function (?string $name = 'John') {6 return $name;7});
正則表示式約束
您可以使用路由例項上的 where 方法來約束路由引數的格式。where 方法接受引數名稱和一個定義引數約束方式的正則表示式。
1Route::get('/user/{name}', function (string $name) { 2 // ... 3})->where('name', '[A-Za-z]+'); 4 5Route::get('/user/{id}', function (string $id) { 6 // ... 7})->where('id', '[0-9]+'); 8 9Route::get('/user/{id}/{name}', function (string $id, string $name) {10 // ...11})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
為方便起見,一些常用的正則表示式模式具有輔助方法,允許您快速向路由新增模式約束。
1Route::get('/user/{id}/{name}', function (string $id, string $name) { 2 // ... 3})->whereNumber('id')->whereAlpha('name'); 4 5Route::get('/user/{name}', function (string $name) { 6 // ... 7})->whereAlphaNumeric('name'); 8 9Route::get('/user/{id}', function (string $id) {10 // ...11})->whereUuid('id');12 13Route::get('/user/{id}', function (string $id) {14 // ...15})->whereUlid('id');16 17Route::get('/category/{category}', function (string $category) {18 // ...19})->whereIn('category', ['movie', 'song', 'painting']);20 21Route::get('/category/{category}', function (string $category) {22 // ...23})->whereIn('category', CategoryEnum::cases());
如果傳入的請求不符合路由模式約束,將返回 404 HTTP 響應。
全域性約束
如果您希望某個路由引數始終受到特定正則表示式的約束,可以使用 pattern 方法。您應該在應用程式 App\Providers\AppServiceProvider 類的 boot 方法中定義這些模式。
1use Illuminate\Support\Facades\Route;2 3/**4 * Bootstrap any application services.5 */6public function boot(): void7{8 Route::pattern('id', '[0-9]+');9}
一旦定義了模式,它就會自動應用於所有使用該引數名稱的路由。
1Route::get('/user/{id}', function (string $id) {2 // Only executed if {id} is numeric...3});
編碼的正斜槓
Laravel 路由元件允許在路由引數值中包含除 / 以外的所有字元。您必須使用 where 條件正則表示式顯式允許 / 作為佔位符的一部分。
1Route::get('/search/{search}', function (string $search) {2 return $search;3})->where('search', '.*');
編碼的正斜槓僅在最後一個路由片段中受支援。
命名路由
命名路由允許為特定路由方便地生成 URL 或重定向。您可以透過在路由定義上鍊式呼叫 name 方法來為路由指定名稱。
1Route::get('/user/profile', function () {2 // ...3})->name('profile');
您也可以為控制器操作指定路由名稱。
1Route::get(2 '/user/profile',3 [UserProfileController::class, 'show']4)->name('profile');
路由名稱應該是唯一的。
為命名路由生成 URL
一旦為給定路由分配了名稱,您就可以在透過 Laravel 的 route 和 redirect 輔助函式生成 URL 或重定向時使用路由名稱。
1// Generating URLs...2$url = route('profile');3 4// Generating Redirects...5return redirect()->route('profile');6 7return to_route('profile');
如果命名路由定義了引數,您可以將引數作為第二個引數傳遞給 route 函式。給定的引數將自動插入到生成 URL 的正確位置。
1Route::get('/user/{id}/profile', function (string $id) {2 // ...3})->name('profile');4 5$url = route('profile', ['id' => 1]);
如果您在陣列中傳遞額外引數,這些鍵值對將自動新增到生成 URL 的查詢字串中。
1Route::get('/user/{id}/profile', function (string $id) {2 // ...3})->name('profile');4 5$url = route('profile', ['id' => 1, 'photos' => 'yes']);6 7// http://example.com/user/1/profile?photos=yes
有時,您可能希望為 URL 引數指定請求範圍內的預設值,例如當前語言環境。為此,您可以使用 URL::defaults 方法。
檢查當前路由
如果您想確定當前請求是否路由到了特定的命名路由,可以在路由例項上使用 named 方法。例如,您可以從路由中介軟體中檢查當前路由名稱。
1use Closure; 2use Illuminate\Http\Request; 3use Symfony\Component\HttpFoundation\Response; 4 5/** 6 * Handle an incoming request. 7 * 8 * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next 9 */10public function handle(Request $request, Closure $next): Response11{12 if ($request->route()->named('profile')) {13 // ...14 }15 16 return $next($request);17}
路由組
路由組允許您在大量路由之間共享路由屬性(如中介軟體),而無需在每個單獨的路由上定義這些屬性。
巢狀組會嘗試智慧地將其屬性與父組“合併”。中介軟體和 where 條件會被合併,而名稱和字首會被追加。名稱空間分隔符和 URI 字首中的斜槓會在適當的時候自動新增。
中介軟體
要將 中介軟體 分配給組內的所有路由,您可以在定義組之前使用 middleware 方法。中介軟體將按照它們在陣列中列出的順序執行。
1Route::middleware(['first', 'second'])->group(function () {2 Route::get('/', function () {3 // Uses first & second middleware...4 });5 6 Route::get('/user/profile', function () {7 // Uses first & second middleware...8 });9});
控制器
如果一組路由都使用相同的 控制器,您可以使用 controller 方法為組內的所有路由定義通用控制器。然後,在定義路由時,您只需提供它們呼叫的控制器方法即可。
1use App\Http\Controllers\OrderController;2 3Route::controller(OrderController::class)->group(function () {4 Route::get('/orders/{id}', 'show');5 Route::post('/orders', 'store');6});
子域名路由
路由組也可用於處理子域名路由。子域名可以像路由 URI 一樣分配路由引數,允許您捕獲子域名的一部分以在路由或控制器中使用。子域名可以透過在定義組之前呼叫 domain 方法來指定。
1Route::domain('{account}.example.com')->group(function () {2 Route::get('/user/{id}', function (string $account, string $id) {3 // ...4 });5});
路由字首
prefix 方法可用於為組內的每個路由新增 URI 字首。例如,您可能希望為組內的所有路由 URI 新增 admin 字首。
1Route::prefix('admin')->group(function () {2 Route::get('/users', function () {3 // Matches The "/admin/users" URL4 });5});
路由名稱字首
name 方法可用於為組內的每個路由名稱新增字首字串。例如,您可能希望為組內所有路由的名稱新增 admin 字首。給定的字串會按指定方式直接作為字首新增到路由名稱中,因此請確保在後綴中包含 . 字元。
1Route::name('admin.')->group(function () {2 Route::get('/users', function () {3 // Route assigned name "admin.users"...4 })->name('users');5});
路由模型繫結
當向路由或控制器操作注入模型 ID 時,您通常會查詢資料庫以檢索與該 ID 對應的模型。Laravel 路由模型繫結提供了一種將模型例項直接自動注入到路由中的便捷方法。例如,您無需注入使用者 ID,而是可以直接注入匹配該 ID 的完整 User 模型例項。
隱式繫結
Laravel 會自動解析路由或控制器操作中定義的 Eloquent 模型,其型別提示變數名稱必須與路由片段名稱匹配。例如:
1use App\Models\User;2 3Route::get('/users/{user}', function (User $user) {4 return $user->email;5});
由於 $user 變數被型別提示為 App\Models\User Eloquent 模型,並且變數名稱與 {user} URI 片段匹配,Laravel 將自動注入 ID 與請求 URI 中的相應值匹配的模型例項。如果在資料庫中找不到匹配的模型例項,將自動生成 404 HTTP 響應。
當然,在使用控制器方法時也可以進行隱式繫結。同樣請注意,{user} URI 片段與控制器中包含 App\Models\User 型別提示的 $user 變數相匹配。
1use App\Http\Controllers\UserController; 2use App\Models\User; 3 4// Route definition... 5Route::get('/users/{user}', [UserController::class, 'show']); 6 7// Controller method definition... 8public function show(User $user) 9{10 return view('user.profile', ['user' => $user]);11}
軟刪除模型
通常,隱式模型繫結不會檢索已被 軟刪除 的模型。但是,您可以透過在路由定義上鍊式呼叫 withTrashed 方法來指示隱式繫結檢索這些模型。
1use App\Models\User;2 3Route::get('/users/{user}', function (User $user) {4 return $user->email;5})->withTrashed();
自定義鍵
有時您可能希望使用 id 以外的列來解析 Eloquent 模型。為此,您可以在路由引數定義中指定該列。
1use App\Models\Post;2 3Route::get('/posts/{post:slug}', function (Post $post) {4 return $post;5});
如果您希望模型繫結在檢索特定模型類時始終使用除 id 之外的資料庫列,則可以覆蓋 Eloquent 模型上的 getRouteKeyName 方法。
1/**2 * Get the route key for the model.3 */4public function getRouteKeyName(): string5{6 return 'slug';7}
自定義鍵與作用域
當在單個路由定義中隱式繫結多個 Eloquent 模型時,您可能希望對第二個 Eloquent 模型進行作用域限定,使其必須是前一個 Eloquent 模型的子級。例如,考慮此透過特定使用者的 slug 檢索部落格文章的路由定義:
1use App\Models\Post;2use App\Models\User;3 4Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {5 return $post;6});
當將自定義鍵隱式繫結用作巢狀路由引數時,Laravel 會自動將查詢範圍限定為透過其父級檢索巢狀模型,並使用約定來猜測父級上的關係名稱。在這種情況下,它將假定 User 模型具有名為 posts(路由引數名稱的複數形式)的關係,該關係可用於檢索 Post 模型。
如果您願意,可以指示 Laravel 即使在未提供自定義鍵的情況下也對“子”繫結進行作用域限定。為此,您可以在定義路由時呼叫 scopeBindings 方法。
1use App\Models\Post;2use App\Models\User;3 4Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {5 return $post;6})->scopeBindings();
或者,您可以指示整組路由定義使用作用域繫結。
1Route::scopeBindings()->group(function () {2 Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {3 return $post;4 });5});
同樣,您可以透過呼叫 withoutScopedBindings 方法顯式指示 Laravel 不要對繫結進行作用域限定。
1Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {2 return $post;3})->withoutScopedBindings();
自定義模型缺失行為
通常,如果找不到隱式繫結的模型,會生成 404 HTTP 響應。但是,您可以透過在定義路由時呼叫 missing 方法來自定義此行為。missing 方法接受一個閉包,如果找不到隱式繫結的模型,該閉包將被呼叫。
1use App\Http\Controllers\LocationsController;2use Illuminate\Http\Request;3use Illuminate\Support\Facades\Redirect;4 5Route::get('/locations/{location:slug}', [LocationsController::class, 'show'])6 ->name('locations.view')7 ->missing(function (Request $request) {8 return Redirect::route('locations.index');9 });
隱式列舉繫結
PHP 8.1 引入了對 列舉 (Enums) 的支援。為了補充此功能,Laravel 允許您在路由定義上對 字串支援的列舉 進行型別提示,只有當該路由片段對應於有效的列舉值時,Laravel 才會呼叫該路由。否則,將自動返回 404 HTTP 響應。例如,給定以下列舉:
1<?php2 3namespace App\Enums;4 5enum Category: string6{7 case Fruits = 'fruits';8 case People = 'people';9}
您可以定義一個只有當 {category} 路由片段為 fruits 或 people 時才會呼叫的路由。否則,Laravel 將返回 404 HTTP 響應。
1use App\Enums\Category;2use Illuminate\Support\Facades\Route;3 4Route::get('/categories/{category}', function (Category $category) {5 return $category->value;6});
顯式繫結
您無需使用 Laravel 基於約定的隱式模型解析即可使用模型繫結。您還可以顯式定義路由引數與模型之間的對應關係。要註冊顯式繫結,請使用路由器的 model 方法來指定特定引數的類。您應該在 AppServiceProvider 類的 boot 方法的開頭定義顯式模型繫結。
1use App\Models\User; 2use Illuminate\Support\Facades\Route; 3 4/** 5 * Bootstrap any application services. 6 */ 7public function boot(): void 8{ 9 Route::model('user', User::class);10}
接下來,定義一個包含 {user} 引數的路由。
1use App\Models\User;2 3Route::get('/users/{user}', function (User $user) {4 // ...5});
由於我們已將所有 {user} 引數繫結到 App\Models\User 模型,該類的例項將被注入到路由中。因此,例如,對 users/1 的請求將注入資料庫中 ID 為 1 的 User 例項。
如果在資料庫中找不到匹配的模型例項,將自動生成 404 HTTP 響應。
自定義解析邏輯
如果您希望定義自己的模型繫結解析邏輯,可以使用 Route::bind 方法。傳遞給 bind 方法的閉包將接收 URI 片段的值,並應返回應注入到路由中的類例項。同樣,此自定義應在應用程式 AppServiceProvider 的 boot 方法中進行。
1use App\Models\User; 2use Illuminate\Support\Facades\Route; 3 4/** 5 * Bootstrap any application services. 6 */ 7public function boot(): void 8{ 9 Route::bind('user', function (string $value) {10 return User::where('name', $value)->firstOrFail();11 });12}
或者,您可以覆蓋 Eloquent 模型上的 resolveRouteBinding 方法。此方法將接收 URI 片段的值,並應返回應注入到路由中的類例項。
1/** 2 * Retrieve the model for a bound value. 3 * 4 * @param mixed $value 5 * @param string|null $field 6 * @return \Illuminate\Database\Eloquent\Model|null 7 */ 8public function resolveRouteBinding($value, $field = null) 9{10 return $this->where('name', $value)->firstOrFail();11}
如果路由正在使用 隱式繫結作用域,則 resolveChildRouteBinding 方法將用於解析父模型的子繫結。
1/** 2 * Retrieve the child model for a bound value. 3 * 4 * @param string $childType 5 * @param mixed $value 6 * @param string|null $field 7 * @return \Illuminate\Database\Eloquent\Model|null 8 */ 9public function resolveChildRouteBinding($childType, $value, $field)10{11 return parent::resolveChildRouteBinding($childType, $value, $field);12}
回退路由
使用 Route::fallback 方法,您可以定義一個當沒有其他路由與傳入請求匹配時執行的路由。通常,未處理的請求會透過應用程式的異常處理程式自動呈現“404”頁面。但是,由於您通常會在 routes/web.php 檔案中定義 fallback 路由,因此 web 中介軟體組中的所有中介軟體都將應用於該路由。您可以根據需要自由地向此路由新增額外的中介軟體。
1Route::fallback(function () {2 // ...3});
速率限制
定義速率限制器
Laravel 包含了強大且可自定義的速率限制服務,您可以利用它來限制給定路由或路由組的流量。要開始使用,您應該定義滿足應用程式需求的速率限制器配置。
速率限制器可以在應用程式 App\Providers\AppServiceProvider 類的 boot 方法中定義。
1use Illuminate\Cache\RateLimiting\Limit; 2use Illuminate\Http\Request; 3use Illuminate\Support\Facades\RateLimiter; 4 5/** 6 * Bootstrap any application services. 7 */ 8public function boot(): void 9{10 RateLimiter::for('api', function (Request $request) {11 return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());12 });13}
速率限制器是使用 RateLimiter 門面的 for 方法定義的。for 方法接受一個速率限制器名稱和一個返回限制配置的閉包,該配置將應用於分配給該速率限制器的路由。限制配置是 Illuminate\Cache\RateLimiting\Limit 類的例項。此類包含有用的“構建器”方法,以便您可以快速定義限制。速率限制器名稱可以是您想要的任何字串。
1use Illuminate\Cache\RateLimiting\Limit; 2use Illuminate\Http\Request; 3use Illuminate\Support\Facades\RateLimiter; 4 5/** 6 * Bootstrap any application services. 7 */ 8public function boot(): void 9{10 RateLimiter::for('global', function (Request $request) {11 return Limit::perMinute(1000);12 });13}
如果傳入的請求超過了指定的速率限制,Laravel 將自動返回一個 429 HTTP 狀態碼的響應。如果您想定義自己的速率限制響應,可以使用 response 方法。
1RateLimiter::for('global', function (Request $request) {2 return Limit::perMinute(1000)->response(function (Request $request, array $headers) {3 return response('Custom response...', 429, $headers);4 });5});
由於速率限制器回撥會接收傳入的 HTTP 請求例項,因此您可以根據傳入的請求或已驗證身份的使用者動態構建適當的速率限制。
1RateLimiter::for('uploads', function (Request $request) {2 return $request->user()?->vipCustomer()3 ? Limit::none()4 : Limit::perHour(10);5});
分段速率限制
有時您可能希望按某個任意值對速率限制進行分段。例如,您可能希望允許使用者按每個 IP 地址每分鐘訪問給定路由 100 次。為此,您可以在構建速率限制時使用 by 方法。
1RateLimiter::for('uploads', function (Request $request) {2 return $request->user()->vipCustomer()3 ? Limit::none()4 : Limit::perMinute(100)->by($request->ip());5});
為了說明此功能,我們可以在另一個示例中將路由訪問限制為:每個已驗證使用者 ID 每分鐘 100 次,或每個訪客 IP 地址每分鐘 10 次。
1RateLimiter::for('uploads', function (Request $request) {2 return $request->user()3 ? Limit::perMinute(100)->by($request->user()->id)4 : Limit::perMinute(10)->by($request->ip());5});
多重速率限制
如果需要,您可以為給定的速率限制器配置返回一個速率限制陣列。每個速率限制將根據它們在陣列中的放置順序對路由進行評估。
1RateLimiter::for('login', function (Request $request) {2 return [3 Limit::perMinute(500),4 Limit::perMinute(3)->by($request->input('email')),5 ];6});
如果您要分配多個由相同 by 值分段的速率限制,請確保每個 by 值都是唯一的。實現這一點的最簡單方法是為傳遞給 by 方法的值新增字首。
1RateLimiter::for('uploads', function (Request $request) {2 return [3 Limit::perMinute(10)->by('minute:'.$request->user()->id),4 Limit::perDay(1000)->by('day:'.$request->user()->id),5 ];6});
基於響應的速率限制
除了限制傳入請求的速率外,Laravel 還允許您使用 after 方法根據響應進行速率限制。當您只想計算某些響應(例如驗證錯誤、404 響應或其他特定 HTTP 狀態碼)對速率限制的影響時,這非常有用。
after 方法接受一個接收響應的閉包,如果響應應計入速率限制,則應返回 true,如果應忽略,則返回 false。這對於透過限制連續的 404 響應來防止列舉攻擊,或者允許使用者重試驗證失敗的請求而不耗盡其在僅應限制成功操作的端點上的速率限制特別有用。
1use Illuminate\Cache\RateLimiting\Limit; 2use Illuminate\Http\Request; 3use Illuminate\Support\Facades\RateLimiter; 4use Symfony\Component\HttpFoundation\Response; 5 6RateLimiter::for('resource-not-found', function (Request $request) { 7 return Limit::perMinute(10) 8 ->by($request->user()?->id ?: $request->ip()) 9 ->after(function (Response $response) {10 // Only count 404 responses toward the rate limit to prevent enumeration...11 return $response->status() === 404;12 });13});
將速率限制器附加到路由
速率限制器可以使用 throttle 中介軟體 附加到路由或路由組。throttle 中介軟體接受您希望分配給路由的速率限制器名稱。
1Route::middleware(['throttle:uploads'])->group(function () {2 Route::post('/audio', function () {3 // ...4 });5 6 Route::post('/video', function () {7 // ...8 });9});
使用 Redis 進行限流
預設情況下,throttle 中介軟體對映到 Illuminate\Routing\Middleware\ThrottleRequests 類。但是,如果您使用 Redis 作為應用程式的快取驅動程式,則可能希望指示 Laravel 使用 Redis 來管理速率限制。為此,您應該在應用程式的 bootstrap/app.php 檔案中使用 throttleWithRedis 方法。此方法將 throttle 中介軟體對映到 Illuminate\Routing\Middleware\ThrottleRequestsWithRedis 中介軟體類。
1->withMiddleware(function (Middleware $middleware): void {2 $middleware->throttleWithRedis();3 // ...4})
表單方法偽造
HTML 表單不支援 PUT、PATCH 或 DELETE 操作。因此,在定義從 HTML 表單呼叫的 PUT、PATCH 或 DELETE 路由時,您需要向表單新增一個隱藏的 _method 欄位。隨 _method 欄位傳送的值將被用作 HTTP 請求方法。
1<form action="/example" method="POST">2 <input type="hidden" name="_method" value="PUT">3 <input type="hidden" name="_token" value="{{ csrf_token() }}">4</form>
為方便起見,您可以使用 @method Blade 指令 來生成 _method 輸入欄位。
1<form action="/example" method="POST">2 @method('PUT')3 @csrf4</form>
訪問當前路由
您可以在 Route 門面上使用 current、currentRouteName 和 currentRouteAction 方法來訪問有關處理傳入請求的路由的資訊。
1use Illuminate\Support\Facades\Route;2 3$route = Route::current(); // Illuminate\Routing\Route4$name = Route::currentRouteName(); // string5$action = Route::currentRouteAction(); // string
您可以參考 API 文件中關於 Route 門面的底層類 和 Route 例項 的內容,以檢視路由器和路由類上所有可用的方法。
跨域資源共享 (CORS)
Laravel 可以自動響應您配置的值的 CORS OPTIONS HTTP 請求。OPTIONS 請求將由自動包含在應用程式全域性中介軟體堆疊中的 HandleCors 中介軟體 自動處理。
有時,您可能需要為您的應用程式自定義 CORS 配置值。您可以使用 config:publish Artisan 命令釋出 cors 配置檔案來完成此操作。
1php artisan config:publish cors
此命令將在應用程式的 config 目錄中放置一個 cors.php 配置檔案。
有關 CORS 和 CORS 頭部的更多資訊,請參閱 MDN 關於 CORS 的 Web 文件。
路由快取
將應用程式部署到生產環境時,您應該利用 Laravel 的路由快取。使用路由快取將極大地減少註冊所有應用程式路由所需的時間。要生成路由快取,請執行 route:cache Artisan 命令。
1php artisan route:cache
執行此命令後,您的快取路由檔案將在每次請求時載入。請記住,如果您添加了任何新路由,則需要生成新的路由快取。因此,您只應在專案部署期間執行 route:cache 命令。
您可以使用 route:clear 命令來清除路由快取。
1php artisan route:clear