跳到內容

路由

基本路由

最基本的 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 中介層群組,該群組提供了諸如 session 狀態和 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');

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 的路由時,應在使用 anymatchredirect 方法的路由之前定義使用 getpostputpatchdeleteoptions 方法的路由。這確保了傳入的請求與正確的路由匹配。

依賴注入

您可以類型提示路由回呼簽名中路由所需的任何依賴項。宣告的依賴項將由 Laravel 服務容器 自動解析並注入到回呼中。例如,您可以類型提示 Illuminate\Http\Request 類,以使當前 HTTP 請求自動注入到您的路由回呼中

1use Illuminate\Http\Request;
2 
3Route::get('/users', function (Request $request) {
4 // ...
5});

CSRF 保護

請記住,任何指向在 web 路由檔案中定義的 POSTPUTPATCHDELETE 路由的 HTML 表單都應包含 CSRF 令牌欄位。否則,請求將被拒絕。您可以在 CSRF 文件中閱讀更多關於 CSRF 保護的資訊

1<form method="POST" action="/profile">
2 @csrf
3 ...
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 保留,不能使用:destinationstatus

視圖路由

如果您的路由只需要返回一個 視圖,您可以使用 Route::view 方法。與 redirect 方法類似,此方法提供了一個簡單的快捷方式,以便您不必定義完整的路由或控制器。view 方法接受 URI 作為其第一個參數,視圖名稱作為其第二個參數。此外,您可以提供一個數據陣列作為可選的第三個參數傳遞給視圖

1Route::view('/welcome', 'welcome');
2 
3Route::view('/welcome', 'welcome', ['name' => 'Taylor']);

當在視圖路由中使用路由參數時,以下參數由 Laravel 保留,不能使用:viewdatastatusheaders

列出你的路由

route:list Artisan 命令可以輕鬆提供應用程式定義的所有路由的概述

1php artisan route:list

預設情況下,分配給每個路由的路由中介層不會顯示在 route:list 輸出中;但是,您可以通過將 -v 選項添加到命令中,指示 Laravel 顯示路由中介層和中介層群組名稱

1php artisan route:list -v
2 
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(): void
7{
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 的 routeredirect 輔助函數生成 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// /user/1/profile?photos=yes

有時,您可能希望為 URL 參數指定請求範圍的預設值,例如當前語言環境。為了實現這一點,您可以使用 URL::defaults 方法

檢查當前路由

如果您想確定當前請求是否路由到給定的命名路由,您可以使用 Route 實例上的 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): Response
11{
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});

為了確保您的子網域路由可訪問,您應該在註冊根網域路由之前註冊子網域路由。這將防止具有相同 URI 路徑的根網域路由覆蓋子網域路由。

路由前綴

prefix 方法可用於為群組中的每個路由添加給定的 URI 前綴。例如,您可能想要為群組中的所有路由 URI 添加 admin 前綴

1Route::prefix('admin')->group(function () {
2 Route::get('/users', function () {
3 // Matches The "/admin/users" URL
4 });
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 匹配的整個 User 模型實例,而不是注入使用者的 ID。

隱式綁定

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(): string
5{
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 引入了對 枚舉 的支援。為了補充此功能,Laravel 允許您在路由定義中類型提示 字串支持的枚舉,並且僅當該路由段與有效的枚舉值對應時,Laravel 才會調用該路由。否則,將自動返回 404 HTTP 回應。例如,給定以下枚舉

1<?php
2 
3namespace App\Enums;
4 
5enum Category: string
6{
7 case Fruits = 'fruits';
8 case People = 'people';
9}

您可以定義一個路由,該路由僅在 {category} 路由段為 fruitspeople 時調用。否則,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 為 1User 實例。

如果在資料庫中找不到匹配的模型實例,將自動生成 404 HTTP 回應。

自訂解析邏輯

如果您希望定義自己的模型綁定解析邏輯,您可以使用 Route::bind 方法。您傳遞給 bind 方法的閉包將接收 URI 段的值,並且應返回應注入到路由中的類別實例。同樣,此自訂應在應用程式 AppServiceProviderboot 方法中進行

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 */
8protected 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 facade 的 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 */
8protected 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::perMinute(100);
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});

將速率限制器附加到路由

速率限制器可以使用 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) {
2 $middleware->throttleWithRedis();
3 // ...
4})

表單方法偽造

HTML 表單不支援 PUTPATCHDELETE 操作。因此,當定義從 HTML 表單調用的 PUTPATCHDELETE 路由時,您需要在表單中添加一個隱藏的 _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 @csrf
4</form>

存取當前路由

您可以使用 Route facade 上的 currentcurrentRouteNamecurrentRouteAction 方法來存取有關處理傳入請求的路由的資訊

1use Illuminate\Support\Facades\Route;
2 
3$route = Route::current(); // Illuminate\Routing\Route
4$name = Route::currentRouteName(); // string
5$action = Route::currentRouteAction(); // string

您可以參考 Route facade 的底層類別Route 實例 的 API 文件,以查看路由器和路由類別上可用的所有方法。

跨來源資源共享 (CORS)

Laravel 可以使用您設定的值自動回應 CORS OPTIONS HTTP 請求。OPTIONS 請求將由自動包含在應用程式全域中介層堆疊中的 HandleCors 中介層 自動處理。

有時,您可能需要自訂應用程式的 CORS 設定值。您可以使用 config:publish Artisan 命令發佈 cors 設定檔來做到這一點

1php artisan config:publish cors

此命令將在應用程式的 config 目錄中放置一個 cors.php 設定檔。

有關 CORS 和 CORS 標頭的更多資訊,請查閱 MDN 網頁上關於 CORS 的文件

路由快取

當您將應用程式部署到正式環境時,應善用 Laravel 的路由快取。使用路由快取將大幅減少註冊應用程式所有路由所需的時間。若要產生路由快取,請執行 route:cache Artisan 指令

1php artisan route:cache

執行此指令後,您的快取路由檔案會在每次請求時載入。請記住,如果您新增任何新路由,則需要產生新的路由快取。因此,您應該僅在專案部署期間執行 route:cache 指令。

您可以使用 route:clear 指令來清除路由快取

1php artisan route:clear