跳至内容

路由

基本路由

最基本的 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文件中定义路由。您可以在浏览器中输入已定义路由的 URL 来访问 中定义的路由。例如,您可以在浏览器中routes/web.php导航到以下路由:http://example.com/user

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

API 路由

如果您的应用程序还提供无状态 API,则可以使用install:apiArtisan 命令启用 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 中间件组。此外,/apiURI 前缀会自动应用于这些路由,因此您无需手动将其应用于文件中的每个路由。您可以通过修改应用程序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方法来实现。或者,您甚至可以使用该方法注册一个响应所有 HTTP 动词的路由any

1Route::match(['get', 'post'], '/', function () {
2 // ...
3});
4 
5Route::any('/', function () {
6 // ...
7});

当定义多个共享相同 URI 的路由时,使用getpostputpatchdeleteoptions方法的路由应先于使用anymatch、 和redirect方法的路由定义。这可确保传入的请求与正确的路由匹配。

依赖注入

你可以在路由的回调签名中输入路由所需的任何依赖项。声明的依赖项将由 Laravel服务容器自动解析并注入到回调中。例如,你可以输入Prompts类Illuminate\Http\Request,将当前的 HTTP 请求自动注入到路由回调中:

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

CSRF保护

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

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

列出你的路线

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

1php artisan route:list

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

1php artisan route:list -v
2 
3# Expand middleware groups...
4php artisan route:list -vv

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

1php artisan route:list --path=api

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

1php artisan route:list --except-vendor

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

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();

然而,有时你可能想要定义一个全新的文件来包含应用程序路由的子集。为此,你可以then为该withRouting方法提供一个闭包。在这个闭包中,你可以注册应用程序所需的任何其他路由:

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)

using或者,你甚至可以通过在方法中提供一个闭包来完全控制路由注册withRouting。传递此参数后,框架将不会注册任何 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中定义以下模式bootApp\Providers\AppServiceProvider

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', '.*');

编码的正斜杠仅在最后一段路线内受支持。

命名路由

name命名路由可以方便地为特定路由生成 URL 或重定向。你可以在路由定义中链接以下方法来指定路由名称:

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

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

1Route::get(
2 '/user/profile',
3 [UserProfileController::class, 'show']
4)->name('profile');

路线名称应始终是唯一的。

生成命名路由的 URL

一旦为给定的路由分配了名称,您就可以在通过 Laravelrouteredirect辅助函数生成 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 方法

检查当前路线

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

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 路由模型绑定提供了一种便捷的方法,可以将模型实例直接自动注入到路由中。例如,你可以注入与User给定 ID 匹配的整个模型实例,而不是注入用户 ID。

隐式绑定

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

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

由于$user变量的类型Prompts为App\Models\UserEloquent 模型,且变量名与{user}URI 片段匹配,Laravel 会自动注入 ID 与请求 URI 中对应值匹配的模型实例。如果在数据库中找不到匹配的模型实例,则会自动生成 404 HTTP 响应。

当然,使用控制器方法时也可以进行隐式绑定。再次注意, URI 段与控制器中包含类型Prompts的变量{user}匹配:$userApp\Models\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();

自定义键

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

1use App\Models\Post;
2 
3Route::get('/posts/{post:slug}', function (Post $post) {
4 return $post;
5});

如果您希望模型绑定总是使用数据库列(除了id检索给定的模型类时),您可以重写getRouteKeyNameEloquent 模型上的方法:

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

类似地,您可以通过调用该方法明确指示 Laravel 不要限制绑定范围withoutScopedBindings

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 允许你在路由定义中使用类型Prompts来指定一个字符串类型的枚举,并且只有当该路由段对应于有效的枚举值时,Laravel 才会调用该路由。否则,将自动返回 404 HTTP 响应。例如,给定以下枚举:

1<?php
2 
3namespace App\Enums;
4 
5enum Category: string
6{
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开头定义显式模型绑定bootAppServiceProvider

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将从UserID 为 的数据库中注入一个实例1

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

自定义解析逻辑

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

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}

或者,你可以重写resolveRouteBindingEloquent 模型上的方法。该方法将接收 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”页面。但是,由于您通常会在文件fallback中定义该路由routes/web.php,因此中间件组中的所有中间件都web将应用于该路由。您可以根据需要向此路由添加其他中间件:

1Route::fallback(function () {
2 // ...
3});

速率限制

定义速率限制器

Laravel 包含强大且可自定义的速率限制服务,您可以使用它们来限制指定路由或一组路由的流量。首先,您需要定义符合应用程序需求的速率限制器配置。

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

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 可以使用中间件将速率限制器附加到路由或路由组。节流中间件接受你希望分配给路由的速率限制器的名称:

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 来管理速率限制。为此,你应该throttleWithRedis在应用程序bootstrap/app.php文件中使用该方法。此方法将throttle中间件映射到Illuminate\Routing\Middleware\ThrottleRequestsWithRedis中间件类:

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->throttleWithRedis();
3 // ...
4})

表单方法欺骗

HTML 表单不支持PUTPATCHDELETE操作。因此,在定义从 HTML 表单调用的 、 或 路由时,您需要向表单添加一个隐藏PUT字段PATCH随该字段发送的值将用作 HTTP 请求方法:DELETE_method_method

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>

访问当前路线

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

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

您可以参考Route 外观的底层类Route 实例的API 文档来查看路由器和路由类上可用的所有方法。

跨域资源共享(CORS)

Laravel 可以自动响应OPTIONS你配置的 CORS HTTP 请求。这些请求将由应用程序全局中间件栈中自动包含的中间件OPTIONS自动处理。HandleCors

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

1php artisan config:publish cors

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

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

路由缓存

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

1php artisan route:cache

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

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

1php artisan route:clear