首页 » Laravel 5.3 中文文档 » 正文

「Laravel 5.3 中文文档」HTTP 层 – 路由

基本路由

Laravel 最基本的路由接收一个 URI 和一个 Closure 闭包,提供一个简单的、生动的方法定义路由:

Route::get('foo', function () {
    return 'Hello World';
});

默认路由文件

Laravel 所有的路由都定义在路由文件中,存放在 routes 目录中。这些文件会被框架自动加载。routes/web.php 文件为你的 WEB 接口定义路由。这些路由会被分配在 web 中间件组下,提供了 session 状态及 CSRF 保护等功能。routes/api.php 文件中的路由是无状态的,并被分配在 api 中间件组下。

对于大多数应用,路由都是定义在 routes/web.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'], '/', function () {
    //
});

Route::any('foo', function () {
    //
});

CSRF 保护

任何定义在 web 路由文件中的指向 POSTPUT 或 DELETE 路由的 HTML 表单,都应当包含一个 CSRF token 字段。否则,请求将会被拒绝。你可以在 CSRF 文档中了解更多关于 CSRF 保护的内容:

<form method="POST" action="/profile">
    {{ csrf_field() }}
    ...
</form>

路由参数

基础路由参数

有时候你可能需要从你的 URI 路由中来获取一些参数。例如,你需要从 URL 中获取用户的 ID。你可以这样定义路由参数:

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

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

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

路由参数都需要大括号 {} 包住,并由字母字符组成。路由参数不可以包含 - 字符,请使用下划线 _ 代替。

可选参数

有时候你可能需要指定路由参数,但需要路由参数是可选的。你可以通过在参数名后放一个 ? 来实现。需要确保给相应的变量赋以默认值:

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

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

命名路由

命名路由让你可以更方便的为特定路由生成 URL 或进行重定向。你可以在路由定义后链式调用 name 方法为路由指定名称:

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

你也可以为控制器方法路由指定参数:

Route::get('user/profile', 'UserController@showProfile')->name('profile');

为命名路由生成 URLs

一旦你为一个给定的路由指定了名称,当生成 URLs 的时候你可以使用路由名称或使用全局的 route 方法:

// Generating URLs...
$url = route('profile');

// Generating Redirects...
return redirect()->route('profile');

如果命名路由定义了参数,你可以把参数作为第二个参数传递给 route 函数。指定的参数将自动添加到 URL 的正确位置上:

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

$url = route('profile', ['id' => 1]);

路由组

路由组允许你在多个路由中分享路由参数,例如中间件或命名空间,而不需要在每个路由中单独定义这些参数。分享的路由参数会以数组的形式作为第一个参数传递给 Route::group 方法。

中间件

要为一组路由指定中间件,需要在组属性数组中使用 middleware 键。中间件将会依照列表内指定的顺序运行:

Route::group(['middleware' => 'auth'], function () {
    Route::get('/', function ()    {
        // Uses Auth Middleware
    });

    Route::get('user/profile', function () {
        // Uses Auth Middleware
    });
});

命名空间

另一个常用的情况是为一组控制器指定相同的 PHP 命名空间,通过在 group 数组中使用 namespace 参数来实现:

Route::group(['namespace' => 'Admin'], function() {
    // Controllers Within The "App\Http\Controllers\Admin" Namespace
});

记住,默认情况下,RouteServiceProvider 会把你的路由文件包含在一个命名空间组内,允许你在不需要指定全部 App\Http\Controllers 命名空间前缀就可以注册路由。所以,你只需指定位于 App\Http\Controllers 之后的一部分命名空间即可。

子域名路由

路由组还可以用来处理子域名路由。子域名可以像路由 URI 那样通过路由参数来指定,让你捕获子域名的部分以便在路由或控制器中使用。子域名可以通过在组属性数组中设置 domain 键来指定。

Route::group(['domain' => '{account}.myapp.com'], function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});

路由前缀

prefix 组属性可以用来为组中每一个路由加上一个给定的 URI 前缀。例如,你想为组中所有路由加上 admin 前缀:

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

路由模型绑定

当注入一个模型 ID 到路由或控制器方法时,你经常会需要取回对应 ID 的模型。Laravel 路由模型绑定提供了一中方便的方式自动注入模型实例到你的路由。例如,你可以将匹配给定 ID 的整个 User 类实例注入到路由中,而不是直接注入用户 ID。

隐式绑定

Laravel 会自动解析定义在路由或控制器方法中与路由片段匹配的 Eloquent 模型类型声明,例如:

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

在这个例子中,由于 Eloquent 中定义的 $user 变量与路由 URI 中的 {user} 相匹配,Laravel 会自动注入与请求 URI 中与 ID 的值相应的模型实例。如果匹配的模型实例在数据库中没找到,则会自动生成一个 404 状态的 HTTP 响应。

自定义键名

当要获取一个给定的模型时,如果你想隐式绑定使用 ID 以外的数据库字段,那么你可以在 Eloquent 模型中重写 getRouteKeyName 方法:

/**
 * 获取模型的路由键值
 *
 * @return string
 */
public function getRouteKeyName()
{
    return 'slug';
}

显式绑定

要注册显式绑定,请使用路由的 model 方法来指定给定参数的类名。你需要在 RouteServiceProvider 类的 boot 方法中来定义你的显式模型绑定:

public function boot()
{
    parent::boot();

    Route::model('user', 'App\User');
}

然后定义一个包含 {user} 参数的路由:

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

由于我们已经把 {user} 参数与 App\User 模型绑定到了一起,因此 User 实例将会被注入到路由中。例如,profile/1 请求将会把数据库中 ID 为 1 的 User 实例注入到路由。

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

自定义解析逻辑

如果你想使用自己的解析逻辑,你可以使用 Route::bind 方法。你传递给 bind 方法的匿名函数将接收 URI 参数的值,并返回需要注入到路由中的类的实例。

表单方法欺骗

HTML 表单不支持 PUTPATCHDELETE 方法。所以,当定义需要在 HTML 表单中调用的  PUTPATCHDELETE 路由时,你需要为表单添加一个 _method 隐藏域。_method 的值将会被用作 HTTP 请求的方法:

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

你可以使用 method_field 方法来生成 _method 隐藏域:

{{ method_field('PUT') }}

访问当前路由

你可以在 Route Facade上使用 currentcurrentRouteName、以及 currentRouteAction 方法来得到当前进入请求的信息:

$route = Route::current();

$name = Route::currentRouteName();

$action = Route::currentRouteAction();

参考 Route facade 的底层类以及 Route 实例的 API 文档来获取更多信息。


该篇属于专题:《Laravel 5.3 中文文档

本文共 2 个回复

  • public 2016/08/31 09:41

    感谢楼主,5.3中为何不见路由正则?不支持了吗?另在5.3中使用5.2中的Global Constraints 报错Declaration of App\Providers\RouteServiceProvider::boot(Illuminate\Routing\Router $router) should be compatible with Illuminate\Foundation\Support\Providers\RouteServiceProvider::boot()求解释

    • Specs 2016/08/31 21:35

      @ public Illuminate\Routing\Router 这个改成 Facade, 用 use Route 试试。参考自 laracasts.com/discuss/channels/laravel/l53-routeserviceprovider-update

发表评论