路由


路由入门

基本使用

最基本的 Laravel 路由只接收一个 URI 和一个闭包,并以此为基础提供一个非常简单优雅 的路由定义方法:

Route::get('hello', function () {
    return 'Hello Laravel!';
});

我们以在安装配置文档中新建的 blog 应用为例,在 routes/web.php 中定义该路由:

-w1198

然后在 blog 项目根目录下通过命令行启动内置 Web 服务器:

php artisan serve

-w578

就可以在浏览器中通过 http://127.0.0.1:8000/hello 即可访问我们刚刚定义的路由,页面输出内容如下:

Hello Laravel!

默认路由文件

所有 Laravel 路由都定义在位于 routes 目录下的路由文件中,这些文件通过框架自动加载,相应逻辑位于 app/Providers/RouteServiceProvider 类。routes/web.php 文件定义了 Web 界面的路由,这些路由被分配到了 web 中间件组,从而可以使用 Session 和 CSRF 保护等功能。routes/api.php 中的路由是无状态的,这是因为被分配到了 api 中间件组。

对大多数应用而言,都是从 routes/web.php 文件开始定义路由。定义在 routes/web.php 中的路由可以通过在浏览器地址栏输入相应的 URL 进行访问,例如,你可以通过 http://blog.test/user 访问下面的路由:

use App\Http\Controllers\UserController;

Route::get('/user', [UserController::class, 'index']);

定义在 routes/api.php 文件中的路由通过 app/Providers/RouteServiceProvider 的处理被嵌套在一个路由群组中,在这个群组中,所有路由会被自动添加 /api 前缀,所以你不需要再到路由文件中为每个路由手动添加,你可以通过编辑 RouteServiceProvider 类来修改路由前缀以及其他的路由群组选项:

/**
 * Define your route model bindings, pattern filters, etc.
 *
 * @return void
 */
public function boot()
{
    $this->configureRateLimiting();

    $this->routes(function () {
        Route::middleware('web')
            ->group(base_path('routes/web.php'));

        Route::prefix('api')
            ->middleware('api')
            ->group(base_path('routes/api.php'));
    });
}

有效的路由器方法

我们可以通过路由器注册路由来响应任何 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'], 'foo', function () {
    return 'This is a request from get or post';
});
    
Route::any('bar', function () {
    return 'This is a request from any HTTP verb';
});

测试 GET 请求的时候直接在浏览器中输入请求地址即可,测试 POST 请求可以通过客户端工具,比如 Postman,此外如果上面的路由是定义在 routes/web.php 的话,在测试 POST 请求之前,需要将对应路由取消 CSRF 保护检查,否则会返回 419 状态码导致无法请求成功,取消的方法是在 app/Http/Middleware/VerifyCsrfToken 中设置排除检查路由:

-w997

下面我们来测试下 POST 请求:

-w961

如果路由是定义在 routes/api.php 的话,则无需关注 CSRF 保护问题,比如我们在 routes/api.php 定义 bar 路由,并且在 VerifyCsrfToken$except 属性数组中移除 bar,然后我们测试下对 http://127.0.0.1/api/bar 的 POST 请求:

-w964

正如我们所预测的,完全没有任何问题,背后的原因是因为 Web 路由文件中定义的路由都位于 web 中间件群组,该群组默认启用 CSRF 保护检查,而 API 路由文件位于 api 路由群组,该群组下的路由主要用于 第三方 API 请求,没办法进行 CSRF 检查,所以不需要做任何处理。

CSRF 保护

routes/web.php 路由文件中所有请求方式为 PUTPOSTDELETE 的路由对应的 HTML 表单都必须包含一个 CSRF 令牌字段,否则,请求会被拒绝。关于 CSRF 的更多细节,可以参考 CSRF 文档

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

还是以上面的 foo 路由为例,如果我们不在 VerifyCsrfToken 中间件中排除对它的检查(事实上,这样的操作也不安全),那么就需要在表单提交中带上 csrf_token 字段:

这样,当我们访问 http://127.0.0.1:8000/form 然后在页面点击提交按钮后,页面会跳转到 http://127.0.0.1:8000/foo 并显示如下内容:

This is a request from get or post

重定向路由

如果你需要定义一个重定向到其他 URI 的路由,可以使用 Route::redirect 方法,该方法非常方便,以至于你不需要再定义额外的路由或控制器来执行简单的重定向逻辑:

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

其中 here 表示原路由,there 表示重定向之后的路由。默认情况下,Route::redirect 返回 302 状态码,你可以使用可选的第三个参数来自定义这个状态码:

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

你还可以使用 Route::permanentRedirect 方法来返回 301 状态码:

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

视图路由

如果你的路由需要返回一个视图,可以使用 Route::view 方法,和 redirect 方法类似,这个方法也很方便,以至于你不需要在额外定义一个路由或控制器。view 方法接收一个 URI 作为第一个参数,以及一个视图名称作为第二个参数,此外,你还可以提供一个数组数据传递到该视图方法作为可选的第三个参数,该数组数据可用于视图中的数据渲染:

Route::view('/welcome', 'welcome');
Route::view('/welcome', 'welcome', ['name' => '学院君']);

我们在 routes/web.php 定义一个路由视图如下:

Route::view('hello', 'hello', ['name' => '学院君']);

然后在 resources/views 目录下新建一个视图模板文件 hello.blade.php,并初始化视图模板代码如下:

<h1>
    Hello, {{ $name }}!
</h1>

我们将原来写死的 Laravel 文本调整为支持变量传入的方式,这样,我们就可以在浏览器中通过 http://127.0.0.1:8000/hello 访问路由视图了:

-w593

路由参数

必选参数

有时我们需要在路由中获取 URI 请求参数。例如,如果要从 URL 中获取用户ID,需要通过如下方式定义路由参数:

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

这样我们在浏览器中访问 http://127.0.0.1:8000/user/1,就会得到以下输出:

User 1

可以根据需要在路由中定义多个路由参数:

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

根据上面的示例,路由参数需要通过花括号 {} 进行包裹并且是拼音字母,这些参数在路由被执行时会被传递到路由的闭包。路由参数名称不能包含 - 字符,如果需要的话可以使用 _ 替代,比如如果某个路由参数定义成 {post-id} 则访问路由会报错,应该修改成 {post_id} 才行。路由参数被注入到路由回调/控制器取决于它们的顺序,与回调/控制器名称无关。

可选参数

有必选参数就有可选参数,这可以通过在参数名后加一个 ? 标记来实现,这种情况下需要给相应的变量指定默认值,当对应的路由参数为空时,使用默认值:

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

这时如果定义的路由是下面这个的话,访问 http://127.0.0.1:8000/user 会返回 John

正则约束

可以通过路由实例上的 where 方法来约束路由参数的格式。where 方法接收参数名和一个正则表达式来定义该参数如何被约束:

Route::get('user/{name}', function ($name) {
    // $name 必须是字母且不能为空
})->where('name', '[A-Za-z]+');
    
Route::get('user/{id}', function ($id) {
    // $id 必须是数字
})->where('id', '[0-9]+');
    
Route::get('user/{id}/{name}', function ($id, $name) {
    // 同时指定 id 和 name 的数据格式
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

使用正则约束还有一个好处就是避免了 user/{id}user/{name} 的混淆。

全局约束

如果想要路由参数在全局范围内被给定正则表达式约束,可以使用 pattern 方法。需要在 RouteServiceProvider 类的 boot 方法中定义这种约束模式:

/**
 * 定义路由模型绑定,模式过滤器等
 *
 * @param  \Illuminate\Routing\Router  $router
 * @return void
 * @translator  http://laravelacademy.org
 */
public function boot()
{
    Route::pattern('id', '[0-9]+');
}

一旦模式被定义,将会自动应用到所有包含该参数名的路由中:

Route::get('user/{id}', function ($id) {
    // 只有当 {id} 是数字时才会被调用
});

除此之外,该模式还会被应用到诸如下面这些路由参数上:

Route::get('post/{id}', function ($id) {
    // 只有当 {id} 是数字时才会被调用
});
    
Route::get('product/{id}', function ($id) {
    // 只有当 {id} 是数字时才会被调用
});

很显然这种方式让代码更简洁,也为我们实现同一参数统一约束带来了方便。

对斜杠进行编码

Laravel 路由组件支持除 / 之外的所有字符,如果要在占位符中使用 / 需要通过 where 条件正则表达式显式允许:

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

注:只有最后一个路由参数片段中才支持编码正斜杠/

命名路由

命名路由为生成 URL 或重定向提供了方便,实现起来也很简单,在路由定义之后使用 name 方法链的方式来定义该路由的名称:

Route::get('user/profile', function () {
    // 通过路由名称生成 URL
    return 'my url: ' . route('profile');
})->name('profile');

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

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

这样我们就可以通过以下方式定义重定向:

Route::get('redirect', function() {
    // 通过路由名称进行重定向
    return redirect()->route('profile');
});

注:路由名称必须是全局唯一的。

为命名路由生成 URL

正如上面代码所展示的,为给定路由分配名称之后,就可以通过辅助函数 route 为该命名路由生成 URL 或者通过 redirect 函数进行重定向:

// 生成URL
$url = route('profile');
    
// 生成重定向
return redirect()->route('profile');

如果命名路由定义了参数,可以将该参数作为第二个参数传递给 route 函数。给定的路由参数将会自动插入到 URL 中:

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

这样,当我们访问 http://127.0.0.1:8000/user/123/profile 页面输出内容也是 http://127.0.0.1:8000/user/123/profile

如果通过数组传入额外参数,这些键/值对将会自动添加到生成的 URL 查询字符串:

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

注:有时候,你可能想要为 URL 参数指定请求范围的默认值,例如当前的时区,这可以通过 URL::defaults 方法实现。

检查当前路由

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

/**
 * 处理输入请求
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    if ($request->route()->named('profile')) {
        //
    }
    
    return $next($request);
}

路由分组

路由分组的目的是让我们在多个路由中共享相同的路由属性,比如中间件和命名空间等,这样的话我们定义了大量的路由时就不必为每一个路由单独定义属性。共享属性以数组的形式作为第一个参数被传递给 Route::group 方法。

嵌套的分组会尝试智能地将属性合并到父分组中,中间件和 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
    });
});

关于中间件的使用我们在后面单独讲中间件时再进行示例演示,这里我们先了解这样使用就行。

子域名路由

路由分组还可以被用于处理子域名路由,子域名可以像 URI 一样被分配给路由参数,从而允许捕获子域名的部分用于路由或者控制器,子域名可以在定义分组之前调用 domain 方法来指定:

Route::domain('{account}.blog.test')->group(function () {
    Route::get('user/{id}', function ($account, $id) {
        return 'This is ' . $account . ' page of User ' . $id;
    });
});

要测试子域名路由,就不能使用 PHP 内置的 Web 服务器了,你需要基于 Valet 或者 Nginx 设置应用域名,假定域名是 blog.test

如果我们设置会员子域名为 account.blog.test,那么就可以通过 http://account.blog.test/user/1 访问用户ID为 1 的会员信息了:

This is account page of User 1

注:为了确保子域名路由生效,需要将子域名路由定义在主域名路由之前,从而避免主域名路由覆盖子域名路由中 URL 路径一致的部分。另外,需要新增 account.blog.test 对应的子域名解析以及在 Nginx 配置文件 server_name 配置项中新增这个子域名,才能让这个子域名路由生效。

路由前缀

prefix 方法可以用来为分组中每个路由添加一个给定 URI 前缀,例如,你可以为分组中所有路由 URI 添加 admin 前缀 :

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

这样我们就可以通过 http://blog.test/admin/users 访问路由了。

路由名称前缀

name 方法可通过传入字符串为分组中的每个路由名称设置前缀,例如,你可能想要在所有分组路由的名称前添加 admin 前缀,由于给定字符串和指定路由名称前缀字符串完全一样,所以需要在前缀字符串末尾后加上 . 字符:

Route::name('admin.')->group(function () {
    Route::get('users', function () {
        // 新的路由名称为 "admin.users"...
    })->name('users');
});

路由模型绑定

注入模型 ID 到路由或控制器动作时,通常需要查询数据库才能获取相应的模型数据。Laravel 路由模型绑定让注入模型实例到路由变得简单,例如,你可以将匹配给定 ID 的整个 User 类实例注入到路由中,而不只是注入用户 ID。

隐式绑定

Laravel 会自动解析定义在路由或控制器动作(变量名匹配路由片段)中的 Eloquent 模型类型声明,例如(我们将这个路由定义在 routes/api.php 文件中):

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

在这个例子中,由于类型声明了 Eloquent 模型 App\Models\User,对应的变量名 $user 会匹配路由片段中的 {user},这样,Laravel 会自动注入与请求 URI 中传入的 ID 对应的用户模型实例。如果匹配模型实例在数据库中不存在,会自动生成 404 响应。

在演示本功能之前,我们需要先创建数据表,由于我是在 Valet 开发环境中开发,需要自己创建数据库,我们将数据库命名为 blog,本地的数据库用户名为 root,密码为空,对应地,修改 .env 文件配置如下:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=blog
DB_USERNAME=root
DB_PASSWORD=

具体配置值以你自己的开发环境设置为准。我们将基于 Laravel 强大的数据库迁移功能创建 users 表,关于数据库迁移后面在数据库部分会详细讨论,这里我们通过以下命令来生成 users 表即可:

php artisan migrate

-w750

进入数据库可以看到该表已经生成:

-w967

这时,users 数据表还没有任何记录,如果数据库中找不到对应的模型实例,会自动生成 HTTP 404 响应,提示页面不存在,所以我们需要在这张表中插入一条记录,这里我们基于 Laravel 强大的数据库填充器来快速完成数据填充功能,首先通过如下命令生成 users 对应的数据表填充器:

php artisan make:seeder UsersTableSeeder

该命令会在 database/seeds 目录下生成一个 UsersTableSeeder 文件,编辑该文件内容如下:

<?php

namespace Database\Seeders;

use Faker\Generator;
use Illuminate\Container\Container;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $faker = $this->withFaker();
        // 插入一条记录到 users 表,通过 Faker 模拟字段值
        DB::table('users')->insert([
            'name' => $faker->name,
            'email' => $faker->unique()->safeEmail,
            'email_verified_at' => now(),
            'password' => bcrypt('secret'),
            'remember_token' => Str::random(10)
        ]);
    }

    /**
     * 获取 Faker 实例
     *
     * @return Generator
     */
    protected function withFaker()
    {
        return Container::getInstance()->make(Generator::class);
    }
}

然后在同目录下 DatabaseSeeder.php 文件的 run 方法中调用 UsersTableSeeder 填充器:

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(UsersTableSeeder::class);
    }
}

最后执行 php artisan db:seed 即可插入对应记录到 users 表了:

-w654

-w1205

这样我们在浏览器中再次访问 http://blog.test/api/users/1 的时候就会显示 User 模型数据了:

-w623

接下来,你就可以在应用代码中直接拿 $user 模型去做你想做的事情了,而不需要自己去数据库查询,从而提高了开发的效率。

自定义键

有时候你可能希望使用 id 之外的其它字段来解析 Eloquent 模型,这可以通过在路由参数定义中指定字段来实现:

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

自定义键&作用域

有时候,在单个路由定义中隐式绑定多个 Eloquent 模型时,你可能想要限定第二个模型必须是第一个模型的从属模型。例如,考虑下面这个通过别名从指定用户会获取某篇文章的场景:

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

使用自定义键的隐式绑定作为嵌套路由参数时,Laravel 会自动将这个查询限定为先使用默认约定规则判定从属关系(基于父模型上的关联关系名称)再通过父模型获取嵌套子模型实例。在这个示例中,会假定 User 模型有一个名为 posts 的关联关系(路由参数名的复数)用于获取 Post 模型实例。

自定义默认键名

如果你想要在模型绑定中使用数据表的其它字段而不是 id 字段,可以重写 Eloquent 模型类的 getRouteKeyName 方法,以 User 模型为例,可以在该模型类中添加这个方法 :

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

这样我们就可以通过 http://blog.test/api/users/Dr. Rigoberto Heaney MD 访问同一个模型实例了。这里需要注意的点是如果该字段不是唯一键,则会返回结果集的第一条记录,对应的底层实现源码位于 Eloquent Model 类的 resolveRouteBinding 方法:

/**
 * 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($field ?? $this->getRouteKeyName(), $value)->first();
}

显式绑定

有隐式绑定,就有显式绑定。要注册显式绑定,可以使用路由器的 model 方法来为给定参数指定绑定类。你需要在 RouteServiceProvider 类的 boot 方法中定义显式模型绑定:

/**
 * Define your route model bindings, pattern filters, etc.
 *
 * @return void
 */
public function boot()
{
    Route::model('user', App\Models\User::class);

    // ...
}

接下来,在 routes/api.php 中定义一个包含 {user} 参数的路由:

$router->get('profile/{user}', function(App\Models\User $user) {
     return $user;
});

由于我们已经绑定 {user} 参数到 App\Models\User 模型,User 实例会被注入到该路由。因此,如果请求 URL 是 http://blog.test/api/profile/1,就会注入一个用户 ID 为 1User 实例:

-w557

如果匹配的模型实例在数据库不存在,会自动生成并返回 HTTP 404 响应:

-w870

自定义解析逻辑

如果你想要使用自定义的解析逻辑,可以在 RouteServiceProvider 类的 boot 方法中使用 Route::bind 方法,传递到 bind 方法的闭包会获取到 URI 请求参数中的值,并且返回你想要在该路由中注入的类实例:

/**
 * Define your route model bindings, pattern filters, etc.
 *
 * @return void
 */
public function boot()
{
    Route::bind('user', function ($value) {
        return App\Models\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();
}

兜底路由

使用 Route::fallback 方法可以定义一个当所有其他路由都未能匹配请求 URL 时所执行的路由。通常,未处理请求会通过 Laravel 的异常处理器自动渲染一个「404」页面,不过,如果你在 routes/web.php 文件中定义了 fallback 路由的话,所有 web 中间件组中的路由都会应用此路由作为兜底,当然,如果需要的话,你还可以添加额外的中间件到此路由:

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

注:兜底路由应该总是放到应用注册的所有路由的最后。

访问频率限制

定义频率限制器

Laravel 内置了功能强大且支持自定义的访问频率限制服务,你可以使用该功能来限制给定路由/路由群组的流量。开始之前,你需要定义符合应用需求的频率限制器配置,通常,这可以在应用自带的 RouteServiceProvider 中完成。

频率限制器通过 RateLimiter 门面的 for 方法定义,该方法接收频率限制器名称和一个返回限制配置(会应用到频率限制器分配到的路由)的闭包作为参数:

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;

RateLimiter::for('global', function (Request $request) {
    return Limit::perMinute(1000);
});

如果进入的请求量超过了指定的频率限制上限,则会自动返回一个状态码为 429 的 HTTP 响应,如果你想要自己定义这个频率限制返回的响应,可以使用 response 方法来定义:

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

由于频率限制器回调接收的是输入的 HTTP 请求实例,因此你可以基于用户请求或者认证用户动态构建相应的频率限制:

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

细分的频率限制

有时候你可能希望通过特定值进一步对频率限制进行细分。例如,你可能想要限定每分钟每个 IP 地址对应的用户只能访问给定路由不超过 100 次,要实现这个功能,你可以在构建频率限制时使用 by 方法:

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

多个频率限制

如果需要的话,你可以为给定频率限制器配置返回频率限制数组,每个频率限制都会基于在数组中的顺序进行执行:

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

应用频率限制器到路由

访问频率限制器可以通过 throttle 中间件应用到路由或者路由群组。throttle 中间件接收频率限制器的名称作为参数,然后再将其通过中间件的形式应用到路由即可:

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

    Route::post('/video', function () {
        //
    });
});

表单方法伪造

HTML 表单不支持 PUTPATCH 或者 DELETE 请求方法,因此,在 HTML 表单中调用 PUTPATCHDELETE 路由时,需要添加一个隐藏的 _method 字段,其值被用作该表单的 HTTP 请求方法:

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

还可以直接使用 Blade 指令 @method 来生成 _method 字段:

<form action="/foo/bar" method="POST">
    @method('PUT')
    @csrf
</form>

访问当前路由

你可以使用 Route 门面上的 currentcurrentRouteNamecurrentRouteAction 方法来访问处理当前输入请求的路由信息:

// 获取当前路由实例
$route = Route::current(); 
// 获取当前路由名称
$name = Route::currentRouteName();
// 获取当前路由action属性
$action = Route::currentRouteAction();

参考 API 文档了解路由门面底层类以及Route实例的更多可用方法。

跨域资源共享(CORS)

Laravel 现在可以自动通过配置值响应 CORS OPTIONS 请求,所有 CORS 设置都可以在配置文件 cors.php 中进行,并且 OPTIONS 请求默认会被 HandleCors 中间件处理(该中间件默认被包含在 Laravel 全局中间件栈中)。

注:更多关于 CORS 和 CORS 响应头信息的细节请参考 CORS 相关的 WDN 文档

实例教程


Vote Vote Cancel Collect Collect Cancel

<< 上一篇: 门面

>> 下一篇: 中间件