Laravel Http 层---路由

1、基本路由

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

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

默认路由文件
有 Laravel 路由都定义在位于 routes 目录下的路由文件中,这些文件通过框架自动加载。
routes/web.php 文件定义了web界面的路由,这些路由被分配了web
中间件组,从而可以提供session和csrf防护等功能。
routes/api.php 中的路由是无状态的,被分配了 api
中间件组。

对大多数应用而言,都是从 routes/web.php 文件开始定义路由。

我们可以注册路由来响应任何 HTTP 请求:

//get 请求
Route::get($uri, $callback);
//post 请求
Route::post($uri, $callback);
//put 请求
Route::put($uri, $callback);
//patch 请求
Route::patch($uri, $callback);
//delete 请求
Route::delete($uri, $callback);
//options 请求
Route::options($uri, $callback);

有时候还需要注册路由响应多个 HTTP 请求——这可以通过 match 方法来实现。或者,可以使用 any 方法注册一个路由来响应所有 HTTP 请求:

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

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

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

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

2、路由参数

必选参数
有时我们需要在路由中捕获 URI 片段。比如,要从 URL 中捕获用户ID,需要通过如下方式定义路由参数:

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

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

Route::get('/hello/{name}/by/{user}',function($name,$user){
    return "Hello {$name} by {$user}!";
});

路由参数总是通过{}进行包裹,这些参数在路由被执行时会被传递到路由的闭包。路由参数不能包含 - 字符,需要的话可以使用 _ 替代。

注意以上参数是必选的,如果没有输入参数会抛出 MethodNotAllowedHttpExceptionNotFoundHttpException 异常。

此外闭包函数中的参数与路由参数一一对应。

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

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

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

Route::get('user/{name}', function ($name) {
    //
})->where('name', '[A-Za-z]+');

Route::get('user/{id}', function ($id) {
    //
})->where('id', '[0-9]+');

Route::get('user/{id}/{name}', function ($id, $name) {
    //
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

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

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

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

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

3、命名路由

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

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

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

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

为命名路由生成URL重定向
给定路由分配名称之后,就可以通过辅助函数 route 为该命名路由生成 URL:

$url = route('profile');
return redirect()->route('profile');

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

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

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

4、路由群组

路由分组就是将一组拥有相同属性(中间件命名空间子域名路由前缀等)的路由使用 Route Facadegroup 方法聚合起来。

共享属性以数组的形式作为第一个参数被传递给 Route::group 方法。

中间件

要给路由群组中定义的所有路由分配中间件,可以在群组属性数组中使用 middleware。中间件将会按照数组中定义的顺序依次执行:

Route::group(['middleware' => 'auth'], function () {
    Route::get('/', function () {
        // 使用 Auth 中间件
    });

    Route::get('user/profile', function () {
        // 使用 Auth 中间件
    });
});

命名空间

命名空间可以通过namespace关键字来设置。

默认情况下, RouteServiceProvider 引入你的路由文件并指定其下所有控制器类所在的默认命名空间App\Http\Controllers,因此,我们在定义的时候只需要指定命名空间 App\Http\Controllers 之后的部分即可 :

Route::group(['namespace' => 'Admin'], function(){
    // 控制器在 "App\Http\Controllers\Admin" 命名空间下
});

子域名路由

子域名可以通过domain关键字来设置 :

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

这样我们在浏览器中访问http://xiao.myapp.com/user/5

路由前缀

路由前缀可以通过 prefix 关键字来设置 :

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

5、路由模型绑定

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

隐式绑定

Laravel 会自动解析定义在路由或控制器动作(变量名匹配路由片段)中的 Eloquent 模型类型声明,例如:

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

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

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

自定义键名
如果你想要在隐式模型绑定中使用数据表的其它字段,可以重写 Eloquent 模型类的 getRouteKeyName 方法:

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

显式绑定

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

public function boot()
{
    parent::boot();
    Route::model('user', App\User::class);
}

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

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

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

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

自定义解析逻辑

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

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

    Route::bind('user', function($value) {
        return App\User::where('name', $value)->first();
    });
}

6、表单方法伪造

HTML 表单不支持 PUTPATCH 或者 DELETE 请求方法,因此,当定义 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>

还可以使用辅助函数 method_field 来实现这一目的:

{{ method_field('PUT') }}

7、访问当前路由

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

$route = Route::current();
$name = Route::currentRouteName();
$action = Route::currentRouteAction();

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容