最基本的 Laravel 路由接受 URI 和闭包,提供了一种非常简单且富有表现力的方法,用于定义路由和行为,无需复杂的路由配置文件:
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 文件中定义路由。在 routes/web.php 中定义的路由,可以通过在浏览器中输入已定义路由的 URL 来访问。例如,您可以通过在浏览器中导航到 http://example.com/user 来访问以下路由:
use App\Http\Controllers\UserController;
Route::get('/user', [UserController::class, 'index']);如果您的应用程序还将提供无状态 API,您可以使用 install:api Artisan 命令启用 API 路由:
php artisan install:apiinstall:api 命令会安装 Laravel Sanctum,它提供一个强大而简单的 API 令牌认证守卫,可用于认证第三方 API 消费者、SPA 或移动应用程序。此外,install:api 命令会创建 routes/api.php 文件:
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');位于routes/api.php的路由是无状态的,并且被分配到api中间件组。此外,/apiURI 前缀会自动应用到这些路由,因此您无需手动将其应用到文件中的每个路由。您可以通过修改应用程序的bootstrap/app.php文件来更改前缀:
->withRouting(
api: __DIR__.'/../routes/api.php',
apiPrefix: 'api/admin',
// ...
)路由器允许您注册可响应任何 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方法的路由之前定义。这可确保传入的请求与正确的路由匹配。
你可以在你的路由回调签名中类型提示你的路由所需的任何依赖。所声明的依赖将由 Laravel 服务容器 自动解析并注入到回调中。例如,你可以类型提示 Illuminate\Http\Request 类,以使当前 HTTP 请求自动注入到你的路由回调中:
use Illuminate\Http\Request;
Route::get('/users', function (Request $request) {
// ...
});请记住,任何在 web 路由文件中定义的、指向 POST、PUT、PATCH 或 DELETE 路由的 HTML 表单都应包含一个 CSRF 令牌字段。否则,请求将被拒绝。您可以在 CSRF 文档中阅读更多关于 CSRF 保护的信息:
<form method="POST" action="/profile">
@csrf
...
</form>如果您正在定义一个重定向到另一个 URI 的路由,您可以使用 Route::redirect 方法。此方法提供了一个便捷的快捷方式,让您无需为执行简单的重定向而定义完整的路由或控制器:
Route::redirect('/here', '/there');默认情况下,Route::redirect 返回 302 状态码。你可以使用可选的第三个参数来自定义状态码:
Route::redirect('/here', '/there', 301);或者,你可以使用Route::permanentRedirect方法来返回一个301状态码:
Route::permanentRedirect('/here', '/there');[!WARNING]
当在重定向路由中使用路由参数时,以下参数被 Laravel 保留,且不能使用:destination和status。
如果你的路由只需要返回一个视图,你可以使用 Route::view 方法。与 redirect 方法类似,此方法提供了一个简单的快捷方式,这样你就不必定义完整的路由或控制器。view 方法接受一个 URI 作为它的第一个参数,以及一个视图名称作为它的第二个参数。此外,你还可以提供一个数据数组,作为可选的第三个参数传递给视图:
Route::view('/welcome', 'welcome');
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);[!WARNING]
在视图路由中使用路由参数时,以下参数被 Laravel 保留,不能使用:view、data、status和headers。
Artisan 命令 route:list 可以轻松提供您的应用程序定义的所有路由的概述:
php artisan route:list默认情况下,分配给每个路由的路由中间件将不会显示在 route:list 输出中;但是,您可以通过向命令添加 -v 选项,指示 Laravel 显示路由中间件和中间件组名称:
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同样地,您也可以指示 Laravel 仅显示由第三方包定义的路由,方法是在执行 route:list 命令时提供 --only-vendor 选项:
php artisan route:list --only-vendor默认情况下,你的应用程序路由由 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 闭包。在此闭包中,你可以注册任何你的应用程序所必需的额外路由:
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 路由,并且你将负责手动注册所有路由:
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'));
},
)Sometimes you will need to capture segments of the URI within your route. For example, you may need to capture a user's ID from the URL. You may do so by defining route parameters:
Route::get('/user/{id}', function (string $id) {
return 'User '.$id;
});您可以根据路由的需要定义任意数量的路由参数:
Route::get('/posts/{post}/comments/{comment}', function (string $postId, string $commentId) {
// ...
});路由参数总是用 {} 大括号括起来,并且应该由字母字符组成。 下划线 (_) 在路由参数名称中也是可以接受的。 路由参数会根据它们的顺序注入到路由回调 / 控制器中 - 路由回调 / 控制器参数的名称不重要。
如果你的路由有你希望 Laravel 服务容器自动注入到你的路由回调中的依赖,你应该在你的依赖之后列出你的路由参数:
use Illuminate\Http\Request;
Route::get('/user/{id}', function (Request $request, string $id) {
return 'User '.$id;
});偶尔你可能需要指定一个不总是存在于 URI 中的路由参数。你可以在参数名称后放置一个 ? 标记来做到这一点。确保为路由对应的变量提供一个默认值:
Route::get('/user/{name?}', function (?string $name = null) {
return $name;
});
Route::get('/user/{name?}', function (?string $name = 'John') {
return $name;
});您可以使用路由实例上的 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]+']);为方便起见,一些常用的正则表达式模式提供了辅助方法,使您能够快速地为路由添加模式约束:
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 响应。
如果你希望路由参数始终受给定正则表达式的约束,可以使用 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...
});Laravel 路由组件允许路由参数值中包含除 / 之外的所有字符。您必须使用 where 条件正则表达式显式地允许 / 成为占位符的一部分:
Route::get('/search/{search}', function (string $search) {
return $search;
})->where('search', '.*');[!WARNING]
编码的正斜杠仅在最后一个路由段中受支持。
命名路由允许方便地为特定路由生成 URL 或重定向。 你可以通过将 name 方法链式调用到路由定义上来为路由指定一个名称:
Route::get('/user/profile', function () {
// ...
})->name('profile');您还可以为控制器动作指定路由名称:
Route::get(
'/user/profile',
[UserProfileController::class, 'show']
)->name('profile');[!警告]
路由名称应始终唯一。
一旦你为给定路由分配了名称,你就可以在通过 Laravel 的 route 和 redirect 辅助函数生成 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 方法。
如果您想确定当前请求是否被路由到给定的命名路由,您可以使用 Route 实例上的 named 方法。例如,您可以从路由中间件中检查当前路由名称:
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);
}路由组允许您在大量路由之间共享路由属性,例如中间件,而无需在每个单独的路由上定义这些属性。
嵌套组尝试智能地“合并”属性与其父组。 中间件和 where 条件被合并,而名称和前缀被附加。 命名空间分隔符和 URI 前缀中的斜杠会在适当的地方自动添加。
为了将 中间件 分配给组内的所有路由,你可以在定义该组之前使用 middleware 方法。中间件将按照它们在数组中列出的顺序执行:
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// Uses first & second middleware...
});
Route::get('/user/profile', function () {
// Uses first & second middleware...
});
});如果一组路由都使用同一个 控制器, 你可以使用 controller 方法 来定义该组内的所有路由的共同控制器。 然后,在定义路由时,你只需提供它们调用的控制器方法即可:
use App\Http\Controllers\OrderController;
Route::controller(OrderController::class)->group(function () {
Route::get('/orders/{id}', 'show');
Route::post('/orders', 'store');
});路由组也可用于处理子域名路由。子域名可以被分配路由参数,就像路由URI一样,允许你捕获子域名的一部分,以便在你的路由或控制器中使用。子域名可以通过在定义组之前调用 domain 方法来指定:
Route::domain('{account}.example.com')->group(function () {
Route::get('/user/{id}', function (string $account, string $id) {
// ...
});
});[!WARNING]
为了确保您的子域路由可访问,您应该在注册根域路由路由之前注册子域路由。这将防止根域路由覆盖具有相同 URI 路径的子域路由。
prefix方法可用于为组中的每个路由添加给定的 URI 前缀。例如,你可能希望为组内的所有路由 URI 添加admin前缀:
Route::prefix('admin')->group(function () {
Route::get('/users', function () {
// Matches The "/admin/users" URL
});
});该 name 方法可用于为组中每个路由名称添加指定字符串前缀。例如,您可能希望用 admin 为组中所有路由的名称添加前缀。所给字符串将严格按照指定方式作为路由名称的前缀,因此请务必在前缀中提供尾部的 . 字符:
Route::name('admin.')->group(function () {
Route::get('/users', function () {
// Route assigned name "admin.users"...
})->name('users');
});当向路由或控制器动作注入模型 ID 时,你通常会查询数据库来检索与该 ID 对应的模型。Laravel 路由模型绑定提供了一种便捷的方式来自动将模型实例直接注入到你的路由中。例如,与其注入用户的 ID,你可以注入与给定 ID 匹配的整个 User 模型实例。
Laravel 自动解析在路由或控制器动作中定义的 Eloquent 模型,其类型提示的变量名匹配路由段名称。例如:
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 响应。
当然, 在使用控制器方法时, 隐式绑定也是可能的. 再次注意, {user} URI 段匹配控制器中包含 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]);
}通常情况下,隐式模型绑定不会检索已经软删除的模型。但是,你可以通过在路由定义上链式调用 withTrashed 方法来指示隐式绑定检索这些模型:
use App\Models\User;
Route::get('/users/{user}', function (User $user) {
return $user->email;
})->withTrashed();有时,您可能希望使用 id 以外的列来解析 Eloquent 模型。 要实现这一点,您可以在路由参数定义中指定该列:
use App\Models\Post;
Route::get('/posts/{post:slug}', function (Post $post) {
return $post;
});如果你希望模型绑定在检索给定模型类时始终使用除了 id 之外的数据库列,你可以重写 Eloquent 模型上的 getRouteKeyName 方法:
/**
* Get the route key for the model.
*/
public function getRouteKeyName(): string
{
return 'slug';
}当在一个路由定义中隐式绑定多个 Eloquent 模型时,你可能希望限定第二个 Eloquent 模型的作用域,使其必须是前一个 Eloquent 模型的子级。例如,考虑这个路由定义,它通过 slug 检索某个特定用户的博客文章:
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 的关系(路由参数名称的复数形式),可用于检索 Post 模型。
如果你愿意,你可以指示 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;
});
});类似地,你可以明确地指示 Laravel 不进行绑定作用域,通过调用 withoutScopedBindings 方法:
Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
return $post;
})->withoutScopedBindings();通常情况下,如果隐式绑定的模型未找到,会生成一个 404 HTTP 响应。然而,你可以在定义路由时通过调用 missing 方法来自定义此行为。missing 方法接受一个闭包,该闭包将在隐式绑定的模型无法找到时被调用:
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 允许您在路由定义中类型提示 字符串支持的枚举,并且仅当该路由段对应于有效的枚举值时,Laravel 才会调用该路由。否则,将自动返回 404 HTTP 响应。例如,给定以下枚举:
<?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;
});你不需要使用 Laravel 的隐式、基于约定的模型解析才能使用模型绑定。你也可以显式定义路由参数如何与模型对应。要注册一个显式绑定,请使用路由器的 model 方法来指定给定参数的类。你应当在你的 AppServiceProvider 类的 boot 方法的开头定义你的显式模型绑定:
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 模型,该类的一个实例将被注入到路由中。因此,例如,对 users/1 的请求将注入来自数据库的 User 实例,其 ID 为 1。
如果数据库中未找到匹配的模型实例,将自动生成一个 404 HTTP 响应。
如果您希望定义自己的模型绑定解析逻辑,您可以使用 Route::bind 方法。您传递给 bind 方法的闭包将接收 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 模型上的 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 方法将被用来解析父模型的子绑定:
/**
* 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 文件中定义 fallback 路由,web 中间件组中的所有中间件都将应用于该路由。你可以根据需要为该路由添加额外的中间件:
Route::fallback(function () {
// ...
});Laravel 包含强大且可定制的速率限制服务,你可以利用它们来限制给定路由或路由组的流量。要开始使用,你应该定义符合你的应用程序需求的速率限制器配置。
限流器可以在应用程序的 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());
});
}速率限制器使用 RateLimiter 外观的 for 方法定义。for 方法接受一个速率限制器名称和一个闭包,该闭包返回应应用于分配给该速率限制器的路由的限制配置。限制配置是 Illuminate\Cache\RateLimiting\Limit 类的实例。此类包含有用的“构建器”方法,以便您可以快速定义您的限制。速率限制器名称可以是您希望的任何字符串:
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);
});
});鉴于限速器回调接收传入的 HTTP 请求实例, 您可以基于传入请求或已认证用户动态构建适当的限速 :
RateLimiter::for('uploads', function (Request $request) {
return $request->user()->vipCustomer()
? Limit::none()
: Limit::perHour(10);
});有时您可能希望依据某个任意值对速率限制进行分段。例如,您可能希望允许用户每分钟每个 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());
});如果需要,你可以为给定的限速器配置返回一个限速数组。每个限速都将根据其在数组中的放置顺序,针对该路由进行评估:
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),
];
});除了限制传入请求的速率外,Laravel 还允许你使用 after 方法根据响应进行速率限制。这在你只想将特定响应计入速率限制时非常有用,例如验证错误、404 响应或其他特定的 HTTP 状态码。
after 方法接受一个闭包,该闭包接收响应,并且如果响应应该计入速率限制,则应返回 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;
});
});速率限制器可以使用 throttle 中间件 附加到路由或路由组。throttle 中间件接受您希望分配给路由的速率限制器名称:
Route::middleware(['throttle:uploads'])->group(function () {
Route::post('/audio', function () {
// ...
});
Route::post('/video', function () {
// ...
});
});默认情况下,throttle 中间件映射到 Illuminate\Routing\Middleware\ThrottleRequests 类。然而,如果你正在使用 Redis 作为应用程序的缓存驱动,你可能希望指示 Laravel 使用 Redis 来管理速率限制。为此,你应该在你的应用程序的 bootstrap/app.php 文件中使用 throttleWithRedis 方法。此方法会将 throttle 中间件映射到 Illuminate\Routing\Middleware\ThrottleRequestsWithRedis 中间件类:
->withMiddleware(function (Middleware $middleware): void {
$middleware->throttleWithRedis();
// ...
})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>您可以使用 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 文档,以查阅路由器和路由类上所有可用的方法。
Laravel 可以自动响应 CORS OPTIONS HTTP 请求,并带上您配置的值。这些 OPTIONS 请求将自动由 HandleCors 中间件 处理,该中间件自动包含在您的应用程序的全局中间件堆栈中。
有时,您可能需要为您的应用程序自定义 CORS 配置值。您可以通过发布 cors 配置文件,使用 config:publish Artisan 命令:
php artisan config:publish cors此命令将在你的应用的 config 目录中放置一个 cors.php 配置文件。
[!注意]
有关 CORS 和 CORS 头的更多信息,请查阅 MDN 关于 CORS 的网络文档。
当将你的应用程序部署到生产环境时,你应该利用 Laravel 的路由缓存。使用路由缓存将大大减少注册所有应用程序路由所需的时间。要生成路由缓存,请执行 route:cache Artisan 命令:
php artisan route:cache运行此命令后,你的缓存路由文件将在每次请求时加载。请记住,如果你添加了任何新路由,你将需要生成一个新的路由缓存。因此,你应该只在项目部署期间运行 route:cache 命令。
你可以使用 route:clear 命令来清除路由缓存:
php artisan route:clear