Skip to content

路由

基本路由

最基本的 Laravel 路由接受 URI 和闭包,提供了一种非常简单且富有表现力的方法来定义路由和行为,而无需复杂的路由配置文件:

php
    use Illuminate\Support\Facades\Route;
    
    Route::get('/greeting', function () {
        return 'Hello World';
    });

默认路由文件

所有 Laravel 路由都在路由文件中定义,路由文件位于 routes 目录中。这些文件由 Laravel 使用应用程序的 bootstrap/app.php 文件中指定的配置自动加载。routes/web.php 文件定义适用于 Web 界面的路由。这些路由被分配了 Web中间件组,该组提供会话状态和 CSRF 保护等功能。

对于大多数应用程序,您将首先在 routes/web.php 文件中定义路由。可以通过在浏览器中输入定义的路由的 URL 来访问 routes/web.php 中定义的路由。例如,您可以通过在浏览器中导航到 http://example.com/user 来访问以下路由:

php
    use App\Http\Controllers\UserController;
    
    Route::get('/user', [UserController::class, 'index']);

API 路由

如果您的应用程序还将提供无状态 API,则可以使用 install:api Artisan 命令启用 API 路由:

shell
php artisan install:api

install:api 命令安装 Laravel Sanctum,它提供了一个强大而简单的 API 令牌身份验证保护,可用于对第三方 API 使用者、SPA 或移动应用程序进行身份验证。此外,install:api 命令会创建 routes/api.php 文件:

php
    Route::get('/user', function (Request $request) {
        return $request->user();
    })->middleware('auth:sanctum');

routes/api.php 中的路由是无状态的,并分配给 api中间件组。此外,/api URI 前缀会自动应用于这些路由,因此您无需手动将其应用于文件中的每个路由。您可以通过修改应用程序的 bootstrap/app.php 文件来更改前缀:

php
    ->withRouting(
        api: __DIR__.'/../routes/api.php',
        apiPrefix: 'api/admin',
        // ...
    )

可用的路由器方法

路由器允许您注册响应任何 HTTP 谓词的路由:

php
    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 动词的路由:

php
    Route::match(['get', 'post'], '/', function () {
        // ...
    });
    
    Route::any('/', function () {
        // ...
    });

NOTE

在定义共享同一 URI 的多个路由时,使用 getpostputpatchdeleteoptions 方法的路由应在使用 anymatchredirect 方法的路由之前定义。这可确保传入请求与正确的路由匹配。

依赖注入

你可以在路由的回调签名中键入 Hint 路由所需的任何依赖项。声明的依赖项将被 Laravel 服务容器自动解析并注入到回调中。例如,你可以对 Illuminate\Http\Request 类进行 type-hint 操作,将当前的 HTTP 请求自动注入到你的路由回调中:

php
    use Illuminate\Http\Request;
    
    Route::get('/users', function (Request $request) {
        // ...
    });

CSRF 保护

请记住,任何指向 Web 路由文件中定义的 POSTPUTPATCHDELETE 路由的 HTML 表单都应该包含 CSRF 令牌字段。否则,请求将被拒绝。您可以在 CSRF 文档中阅读有关 CSRF 保护的更多信息:

php
    <form method="POST" action="/profile">
        @csrf
        ...
    </form>

重定向路由

如果要定义重定向到另一个 URI 的路由,则可以使用 Route::redirect 方法。此方法提供了一个方便的快捷方式,因此您不必定义完整的路由或控制器来执行简单的重定向:

php
    Route::redirect('/here', '/there');

默认情况下,Route::redirect 返回 302 状态代码。您可以使用可选的第三个参数自定义状态代码:

php
    Route::redirect('/here', '/there', 301);

或者,您可以使用 Route::permanentRedirect 方法返回 301 状态代码:

php
    Route::permanentRedirect('/here', '/there');

WARNING

在重定向路由中使用路由参数时,Laravel 保留以下参数,不能使用:destinationstatus

视图路由

如果你的路由只需要返回一个视图,你可以使用 Route::view 方法。与 redirect 方法一样,此方法提供了一个简单的快捷方式,因此您不必定义完整的路由或控制器。view 方法接受 URI 作为其第一个参数,视图名称作为其第二个参数。此外,你可以提供一个数据数组作为可选的第三个参数传递给视图:

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

WARNING

在 view 路由中使用路由参数时,Laravel 保留了以下参数,不能使用:viewdatastatusheaders

列出你的路由

route:list Artisan 命令可以轻松提供应用程序定义的所有路由的概述:

shell
php artisan route:list

默认情况下,分配给每个路由的路由中间件不会显示在 route:list 输出中;但是,你可以通过在命令中添加 -v 选项来指示 Laravel 显示路由中间件和中间件组名称:

shell
php artisan route:list -v

# 展开中间件组...
php artisan route:list -vv

您还可以指示 Laravel 仅显示以给定 URI 开头的路由:

shell
php artisan route:list --path=api

此外,您可以通过在执行 route:list 命令时提供 --except-vendor 选项来指示 Laravel 隐藏由第三方包定义的任何路由:

shell
php artisan route:list --except-vendor

同样,您也可以通过在执行 route:list 命令时提供 --only-vendor 选项来指示 Laravel 仅显示由第三方包定义的路由:

shell
php artisan route:list --only-vendor

路由自定义

默认情况下,应用程序的路由由 bootstrap/app.php 文件配置和加载:

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 中,您可以注册应用程序所需的任何其他 routes:

php
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 闭包来完全控制路由注册。当传递此参数时,框架不会注册任何 HTTP 路由,您负责手动注册所有路由:

php
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'));
    },
)

路由参数

必需参数

有时,您需要在路由中捕获 URI 的段。例如,您可能需要从 URL 中捕获用户的 ID。您可以通过定义路由参数来实现:

php
    Route::get('/user/{id}', function (string $id) {
        return 'User '.$id;
    });

您可以根据路由的要求定义任意数量的路由参数:

    Route::get('/posts/{post}/comments/{comment}', function (string $postId, string $commentId) {
        // ...
    });

路由参数始终括在 {} 大括号内,并且应由字母字符组成。下划线 (_) 在路由参数名称中也是可以接受的。路由参数根据它们的顺序注入到路由回调/控制器中 - 路由回调/控制器参数的名称无关紧要。

参数和依赖关系注入

如果你的路由有依赖项,你希望 Laravel 服务容器自动注入到路由的回调中,你应该在依赖项后面列出你的路由参数:

php
    use Illuminate\Http\Request;
    
    Route::get('/user/{id}', function (Request $request, string $id) {
        return 'User '.$id;
    });

可选参数

有时,您可能需要指定一个 URI 中可能并不总是存在的路由参数。您可以通过在参数名称后放置 标记来实现此目的。确保为 route 的相应变量提供默认值:

php
    Route::get('/user/{name?}', function (?string $name = null) {
        return $name;
    });
    
    Route::get('/user/{name?}', function (?string $name = 'John') {
        return $name;
    });

正则表达式约束

你可以使用路由实例上的 where 方法约束路由参数的格式。where 方法接受参数的名称和定义应如何约束参数的正则表达式:

php
    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]+']);

为方便起见,一些常用的正则表达式模式具有辅助方法,允许您快速将模式约束添加到路由中:

php
    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 响应。

全局约束

如果你希望 route 参数始终受给定正则表达式的约束,你可以使用 pattern 方法。您应该在应用程序 App\Providers\AppServiceProvider 类的 boot 方法中定义这些模式:

php
    use Illuminate\Support\Facades\Route;
    
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Route::pattern('id', '[0-9]+');
    }

定义模式后,它会自动应用于使用该参数名称的所有路由:

php
    Route::get('/user/{id}', function (string $id) {
        // Only executed if {id} is numeric...
    });

编码的正斜杠

Laravel 路由组件允许路由参数值中出现除 / 之外的所有字符。您必须使用 where 条件正则表达式明确允许 / 成为占位符的一部分:

php
    Route::get('/search/{search}', function (string $search) {
        return $search;
    })->where('search', '.*');

WARNING

编码的正斜杠仅在最后一个路由段中受支持。

命名路由

命名路由允许方便地为特定路由生成 URL 或重定向。你可以通过将 name 方法链接到路由定义来指定路由的名称:

php
    Route::get('/user/profile', function () {
        // ...
    })->name('profile');

您还可以为控制器操作指定路由名称:

php
    Route::get(
        '/user/profile',
        [UserProfileController::class, 'show']
    )->name('profile');

WARNING

路由名称应始终唯一。

生成命名路由的 URL

为给定路由分配名称后,您可以在通过 Laravel 的路由和重定向辅助函数生成 URL 或重定向时使用路由的名称:

php
    // Generating URLs...
    $url = route('profile');
    
    // Generating Redirects...
    return redirect()->route('profile');
    
    return to_route('profile');

如果命名路由定义了参数,则可以将参数作为第二个参数传递给路由函数。给定的参数将自动插入到生成的 URL 中的正确位置:

php
    Route::get('/user/{id}/profile', function (string $id) {
        // ...
    })->name('profile');
    
    $url = route('profile', ['id' => 1]);

如果您在数组中传递其他参数,则这些键/值对将自动添加到生成的 URL 的查询字符串中:

php
    Route::get('/user/{id}/profile', function (string $id) {
        // ...
    })->name('profile');
    
    $url = route('profile', ['id' => 1, 'photos' => 'yes']);
    
    // /user/1/profile?photos=yes

NOTE

有时,您可能希望为 URL 参数指定请求范围的默认值,例如当前区域设置。为此,您可以使用 URL::defaults 方法

检查当前路由

如果你想确定当前请求是否被路由到给定的命名路由,你可以在 Route 实例上使用命名方法。例如,你可以从路由中间件中检查当前路由名称:

php
    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);
    }

路由组

路由组允许您在大量路由之间共享路由属性,例如中间件,而无需在每个单独的路由上定义这些属性。

嵌套组尝试智能地将属性与其父组“合并”。Middleware 和 where 条件合并,同时附加名称和前缀。URI 前缀中的 Namespace 分隔符和斜杠会在适当时自动添加。

中间件

要将 middleware 分配给 Group 内的所有路由,你可以在定义 group 之前使用 middleware 方法。中间件按照它们在数组中列出的顺序执行:

php
    Route::middleware(['first', 'second'])->group(function () {
        Route::get('/', function () {
            // Uses first & second middleware...
        });
    
        Route::get('/user/profile', function () {
            // Uses first & second middleware...
        });
    });

控制器

如果一组路由都使用相同的控制器,则可以使用 controller 方法为组内的所有路由定义公共控制器。然后,在定义路由时,你只需要提供它们调用的控制器方法:

php
    use App\Http\Controllers\OrderController;
    
    Route::controller(OrderController::class)->group(function () {
        Route::get('/orders/{id}', 'show');
        Route::post('/orders', 'store');
    });

子域路由

路由组还可用于处理子域路由。可以像路由 URI 一样为子域分配路由参数,从而允许您捕获子域的一部分,以便在路由或控制器中使用。在定义组之前,可以通过调用 domain 方法来指定子域:

php
    Route::domain('{account}.example.com')->group(function () {
        Route::get('/user/{id}', function (string $account, string $id) {
            // ...
        });
    });

WARNING

为了确保您的子域路由可访问,您应该在注册根域路由之前注册子域路由。这将防止根域路由覆盖具有相同 URI 路径的子域路由。

路由前缀

prefix 方法可用于为组中的每个路由添加给定 URI 的前缀。例如,您可能希望在组内的所有路由 URI 前面加上 admin

php
    Route::prefix('admin')->group(function () {
        Route::get('/users', function () {
            // Matches The "/admin/users" URL
        });
    });

路由名称前缀

name 方法可用于为组中的每个路由名称加上给定字符串的前缀。例如,您可能希望在组中的所有路由的名称前加上 admin。给定的字符串与指定的路由名称完全相同,因此我们确保在前缀中提供尾部 .字符:

php
    Route::name('admin.')->group(function () {
        Route::get('/users', function () {
            // Route assigned name "admin.users"...
        })->name('users');
    });

路由模型绑定

当将模型 ID 注入到路由或控制器操作时,你通常会查询数据库以检索与该 ID 对应的模型。Laravel 路由模型绑定提供了一种将模型实例直接自动注入到路由中的便捷方法。例如,您可以注入与给定 ID 匹配的整个 User 模型实例,而不是注入用户的 ID。

隐式绑定

Laravel 会自动解析路由或控制器操作中定义的 Eloquent 模型,这些模型的类型提示变量名称与路由段名称匹配。例如:

php
    use App\Models\User;
    
    Route::get('/users/{user}', function (User $user) {
        return $user->email;
    });

由于 $user 变量被类型提示为 App\Models\User Eloquent 模型,并且变量名称与 {user} URI 段匹配,因此 Laravel 将自动注入 ID 与请求 URI 中相应值匹配的模型实例。如果在数据库中找不到匹配的模型实例,则将自动生成 404 HTTP 响应。

当然,使用 controller 方法时也可以进行隐式绑定。同样,请注意 {user} URI 段与控制器中的 $user 变量匹配,其中包含 App\Models\User 类型提示:

php
    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]);
    }

软删除模型

通常,隐式模型绑定不会检索已软删除的模型。但是,你可以通过将 withTrashed 方法链接到路由的定义来指示隐式绑定检索这些模型:

php
    use App\Models\User;
    
    Route::get('/users/{user}', function (User $user) {
        return $user->email;
    })->withTrashed();

自定义密钥

有时你可能希望使用 id 以外的列来解析 Eloquent 模型。为此,您可以在 route 参数定义中指定该列:

php
    use App\Models\Post;
    
    Route::get('/posts/{post:slug}', function (Post $post) {
        return $post;
    });

如果你希望模型绑定在检索给定的模型类时始终使用 id 以外的数据库列,你可以覆盖 Eloquent 模型上的 getRouteKeyName 方法:

php
    /**
     * Get the route key for the model.
     */
    public function getRouteKeyName(): string
    {
        return 'slug';
    }

自定义键和范围

当在单个路由定义中隐式绑定多个 Eloquent 模型时,你可能希望限定第二个 Eloquent 模型的范围,使其必须是前一个 Eloquent 模型的子模型。例如,考虑以下路由定义,该定义按 slug 检索特定用户的博客文章:

php
    use App\Models\Post;
    use App\Models\User;
    
    Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
        return $post;
    });

当使用自定义键控隐式绑定作为嵌套路由参数时,Laravel 将自动确定查询范围,以使用约定猜测父级上的关系名称,按其父级检索嵌套模型。在这种情况下,将假定 User 模型具有名为 posts (路由参数 name 的复数形式) 的关系,该关系可用于检索 Post 模型。

如果你愿意,你可以指示 Laravel 对 “child” bindings(子)绑定进行范围限定,即使没有提供自定义键。为此,您可以在定义路由时调用 scopeBindings 方法:

php
    use App\Models\Post;
    use App\Models\User;
    
    Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
        return $post;
    })->scopeBindings();

或者,您可以指示整个路由定义组使用范围绑定:

php
    Route::scopeBindings()->group(function () {
        Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
            return $post;
        });
    });

同样,您可以通过调用 withoutScopedBindings 方法显式指示 Laravel 不对绑定进行范围限定:

php
    Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
        return $post;
    })->withoutScopedBindings();

自定义缺失模型行为

通常,如果未找到隐式绑定模型,将生成 404 HTTP 响应。但是,您可以通过在定义路由时调用 missing 方法来自定义此行为。缺少的方法接受一个闭包,如果找不到隐式绑定模型,将调用该闭包:

php
    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');
            });

隐式枚举绑定

PHP 8.1 引入了对枚举的支持。为了补充此功能,Laravel 允许您在路由定义上对支持的 Enum 进行类型提示,并且 Laravel 仅在该路由段对应于有效的 Enum 值时才会调用该路由。否则,将自动返回 404 HTTP 响应。例如,给定以下 Enum:

php
<?php

namespace App\Enums;

enum Category: string
{
    case Fruits = 'fruits';
    case People = 'people';
}

您可以定义一个路由,该路由仅在 {category} 路由段为 fruitspeople 时调用。否则,Laravel 将返回 404 HTTP 响应:

php
use App\Enums\Category;
use Illuminate\Support\Facades\Route;

Route::get('/categories/{category}', function (Category $category) {
    return $category->value;
});

显式绑定

使用模型绑定时,不需要使用 Laravel 的基于约定的隐式模型解析。您还可以显式定义路由参数与模型的对应方式。要注册显式绑定,请使用 router 的 model 方法为给定参数指定类。您应该在 AppServiceProvider 类的 boot 方法的开头定义显式模型绑定:

php
    use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Route::model('user', User::class);
    }

接下来,定义一个包含 {user} 参数的路由:

php
    use App\Models\User;
    
    Route::get('/users/{user}', function (User $user) {
        // ...
    });

由于我们已经将所有 {user} 参数绑定到 App\Models\User 模型,因此该类的实例将被注入到路由中。因此,例如,对 users/1 的请求将从 ID 为 1 的数据库中注入 User 实例。

如果在数据库中找不到匹配的模型实例,将自动生成 404 HTTP 响应。

自定义解析逻辑

如果您希望定义自己的模型绑定解析逻辑,则可以使用 Route::bind 方法。你传递给 bind 方法的闭包将接收 URI 段的值,并应返回应该注入到路由中的类的实例。同样,此自定义应在应用程序的 AppServiceProviderboot 方法中进行:

php
    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 模型上的 resolveRouteBinding 方法。此方法将接收 URI 段的值,并应返回应注入到路由中的类的实例:

php
    /**
     * 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 方法将用于解析父模型的子绑定:

php
    /**
     * 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);
    }

后备路由

使用 Route::fallback 方法,你可以定义一个路由,当没有其他路由与传入请求匹配时,将执行该路由。通常,未处理的请求将通过应用程序的异常处理程序自动呈现 “404” 页面。但是,由于您通常会在 routes/web.php 文件中定义回退路由,因此 Web 中间件组中的所有中间件都将应用于该路由。您可以根据需要自由地向此路由添加其他中间件:

php
    Route::fallback(function () {
        // ...
    });

WARNING

回退路由应始终是应用程序注册的最后一个路由。

速率限制

定义速率限制器

Laravel 包括功能强大且可定制的速率限制服务,您可以利用这些服务来限制给定路由或路由组的流量。首先,您应该定义满足应用程序需求的速率限制器配置。

速率限制器可以在应用程序 App\Providers\AppServiceProvider 类的 boot 方法中定义:

php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;

/**
 * Bootstrap any application services.
 */
protected function boot(): void
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
    });
}

速率限制器是使用 RateLimiter Facade的 for 方法定义的。for 方法接受速率限制器名称和闭包,该闭包返回应应用于分配给速率限制器的路由的限制配置。Limit 配置是 Illuminate\Cache\RateLimiting\Limit 类的实例。此类包含有用的 “builder” 方法,以便您可以快速定义限制。速率限制器名称可以是您想要的任何字符串:

php
    use Illuminate\Cache\RateLimiting\Limit;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\RateLimiter;
    
    /**
     * Bootstrap any application services.
     */
    protected function boot(): void
    {
        RateLimiter::for('global', function (Request $request) {
            return Limit::perMinute(1000);
        });
    }

如果传入请求超过指定的速率限制,Laravel 将自动返回带有 429 HTTP 状态代码的响应。如果您想定义自己的响应,该响应应由速率限制返回,则可以使用 response 方法:

php
    RateLimiter::for('global', function (Request $request) {
        return Limit::perMinute(1000)->response(function (Request $request, array $headers) {
            return response('Custom response...', 429, $headers);
        });
    });

由于速率限制器回调接收传入的 HTTP 请求实例,因此您可以根据传入请求或经过身份验证的用户动态构建适当的速率限制:

php
    RateLimiter::for('uploads', function (Request $request) {
        return $request->user()->vipCustomer()
                    ? Limit::none()
                    : Limit::perMinute(100);
    });

分段速率限制

有时,您可能希望按某个任意值对速率限制进行分段。例如,您可能希望允许用户每个 IP 地址每分钟访问给定路由 100 次。为此,您可以在构建速率限制时使用 by 方法:

php
    RateLimiter::for('uploads', function (Request $request) {
        return $request->user()->vipCustomer()
                    ? Limit::none()
                    : Limit::perMinute(100)->by($request->ip());
    });

为了使用另一个示例来说明此功能,我们可以将对路由的访问限制为每个经过身份验证的用户 ID 每分钟 100 次,或将访客的每个 IP 地址限制为每分钟 10 次:

php
    RateLimiter::for('uploads', function (Request $request) {
        return $request->user()
                    ? Limit::perMinute(100)->by($request->user()->id)
                    : Limit::perMinute(10)->by($request->ip());
    });

多个速率限制

如果需要,您可以返回给定速率限制器配置的速率限制数组。将根据路由在数组中的放置顺序评估路由的每个速率限制:

php
    RateLimiter::for('login', function (Request $request) {
        return [
            Limit::perMinute(500),
            Limit::perMinute(3)->by($request->input('email')),
        ];
    });

将 Rate Limiter 附加到路由

可以使用 throttle中间件将速率限制器附加到路由或路由组。throttle 中间件接受你希望分配给路由的速率限制器的名称:

php
    Route::middleware(['throttle:uploads'])->group(function () {
        Route::post('/audio', function () {
            // ...
        });
    
        Route::post('/video', function () {
            // ...
        });
    });

使用 Redis 进行限制

默认情况下,throttle 中间件映射到 Illuminate\Routing\Middleware\ThrottleRequests 类。但是,如果您使用 Redis 作为应用程序的缓存驱动程序,您可能希望指示 Laravel 使用 Redis 来管理速率限制。为此,您应该在应用程序的 bootstrap/app.php 文件中使用 throttleWithRedis 方法。此方法将 throttle 中间件映射到 Illuminate\Routing\Middleware\ThrottleRequestsWithRedis middleware 类:

php
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->throttleWithRedis();
        // ...
    })

表单方法欺骗

HTML 表单不支持 PUTPATCHDELETE 操作。因此,在定义从 HTML 表单调用的 PUTPATCHDELETE 路由时,您需要向表单中添加隐藏的 _method 字段。与 _method 字段一起发送的值将用作 HTTP 请求方法:

php
    <form action="/example" method="POST">
        <input type="hidden" name="_method" value="PUT">
        <input type="hidden" name="_token" value="{{ csrf_token() }}">
    </form>

为方便起见,您可以使用 @methodBlade 指令生成 _method 输入字段:

php
    <form action="/example" method="POST">
        @method('PUT')
        @csrf
    </form>

访问当前路由

你可以使用 Route Facade 上的 currentcurrentRouteNamecurrentRouteAction 方法来访问有关处理传入请求的路由的信息:

php
    use Illuminate\Support\Facades\Route;
    
    $route = Route::current(); // Illuminate\Routing\Route
    $name = Route::currentRouteName(); // string
    $action = Route::currentRouteAction(); // string

您可以参考 Route FacadeRoute 实例的底层类的 API 文档,以查看 router 和 route 类上可用的所有方法。

跨域资源共享 (CORS)

Laravel 可以使用您配置的值自动响应 CORS OPTIONS HTTP 请求。OPTIONS 请求将由 HandleCors中间件自动处理,该中间件自动包含在应用程序的全局中间件堆栈中。

有时,您可能需要为应用程序自定义 CORS 配置值。您可以通过使用 config:publish Artisan 命令发布 cors 配置文件来实现这一点:

shell
php artisan config:publish cors

此命令会将cors.php配置文件放置在应用程序的 config 目录中。

NOTE

有关 CORS 和 CORS 标头的更多信息,请参阅有关 CORS 的 MDN Web 文档

路由缓存

将应用程序部署到生产环境时,您应该利用 Laravel 的路由缓存。使用路由缓存将大大减少注册应用程序的所有路由所需的时间。要生成路由缓存,请执行 route:cache Artisan 命令:

shell
php artisan route:cache

运行此命令后,缓存的路由文件将在每个请求中加载。请记住,如果您添加任何新路由,则需要生成新的路由缓存。因此,您应该只在项目部署期间运行 route::cache 命令。

您可以使用 route:clear 命令清除路由缓存:

shell
php artisan route:clear