果冻想
认真玩技术的地方

Laravel初级教程之路由

前言

对于分析一个Web框架,其中最重要的一环就是对这个Web框架的路由进行分析。可以这么说吧,对于一个Web框架,如果你玩不懂它的路由机制,那你也就不可能玩通整个Web框架。可见路由机制在整个Web框架中的地位和重要性。所以,这篇文章将对Laravel框架中的路由机制进行扫盲式的总结,很多内容都参考了Laravel的官方文档,以及网上其他网友分享的内容。后续再对Laravel的路由机制进行源码级别的进阶分析。

基本用法

构建最基本的路由只需要一个URI与一个闭包,这里提供了一个非常简单优雅的定义路由的方法:

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

这段代码的意思是:当访问应用首页http://localhost/hello的时候,返回"Hello World"到浏览器。

在Laravel中,所有路由文件都在routes目录中的路由文件中定义,这些文件都由框架自动加载。在 routes/web.php文件中定义你的web页面路由。这些路由都会应用web中间件组,其提供了诸如SessionCSRF保护等特性。定义在routes/api.php中的路由都是无状态的,并且会应用api中间件组。

我们可以注册路由来响应所有的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);

上面的例子只是返回"Hello World"字符串;更多时候,我们都是在路由中返回视图,比如:

Route::get('/welcome', function () {
    return view('welcome');
});

这段代码的意思是:当访问应用首页http://localhost/welcome的时候,返回/resources/views/welcome.blade.php视图中的内容并渲染到浏览器页面中。

再看一段post路由的代码:

Route::get('/testPost',function(){
    $csrf_token = csrf_token();
    $form = <<<FORM
        <form action="/hello" method="POST">
            <input type="hidden" name="_token" value="{$csrf_token}">
            <input type="submit" value="Test"/>
        </form>
FORM;
    return $form;
});

Route::post('/hello',function(){
    return "Hello Laravel[POST]!";
});

以上是Laravel中路由最基本的用法。接下来说说一些比较高级一点的用法。

路由参数

我们要知道,路由中的每个字段都是有含义的。比如你访问我的博客文章的地址可能是这样:

https://www.jellythink.com/archives/112

URL中的archives表示文章,112表示文章ID;这些都是路由参数。大概了解了路由参数后。再来看看Laravel中的路由参数,我们需要从以下三个方面去了解Laravel中的路由参数:

  • 必选参数
  • 可选参数
  • 正则约束

必选参数,顾名思义就是在URL中必须要携带的参数。比如我们想从URL获取文章ID,需要通过如下方式定义路由参数:

Route::get('/archives/{id}', function($id) {
   return  'archives_id=' . $id;
});

这样我们在浏览器中访问http://localhost/archives/112,就会得到以下输出:

archives_id=112

同理,可以根据业务需要,在路由中定义多个路由参数,像下面这样:

Route::get('archives/{id}/comments/{commentId}', function ($id, $commentId) {
    return $id . '-' . $commentId;
});

注意: 路由参数不能包含-字符。请用下划线_替换。_替换。

可选参数,就是对应的路由参数是可有可无的。如需指定该参数为可选,可以在参数后面加上?来实现,但是相应的变量必须有默认值,这样当对应的路由参数为空时,使用默认值。比如下面这样:

Route::get('user/{name?}', function ($id = 'JellyThink') {
    return "UserName=" . $id;
});

正则约束,则意味着对路由参数的格式,组成类型进行特定的约束。如果无法匹配对应的路由,则抛出404。比如上面的例子,其中的id参数,从业务层次来说,它应该是由数字组成的。那我们如何来约束路由参数为数字呢?这个就需要使用正则约束了,比如可以像下面这样:

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]+']);

但是,有的时候,我们也会遇到这种情况,比如:

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

Route::get('post/{id}', function ($id) {
    // id 必须是数字
})->where('id', '[0-9]+');

Route::get('product/{id}', function ($id) {
    // id 必须是数字
})->where('id', '[0-9]+');

对于上面的路由,我们会发现这些路由都对路由参数id都有相同的约束,那我们是否可以建立一个全局的id约束呢?是的,对于Laravel来说,这是可以的。

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

/**
 * Define your route model bindings, pattern filters, etc.
 *
 * @return void
 */
public function boot()
{
    // 添加id全局约束
    Route::pattern('id', '[0-9]+');
    parent::boot();
}

一旦模式被定义,将会自动应用到所有包含该参数名的路由中。很显然这种方式让代码更简洁,也为我们实现同一参数统一约束带来了方便。

命名路由

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

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

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

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

说白了,路由命名就是给路由定义一个名字,在我们需要使用这个路由的时候,就可以通过这个名字直接,再配合对应的route函数就可以获得完整的URL路径。

路由分组

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

  • 中间件
    中间件为进入应用的HTTP请求提供了一套便利的过滤机制。关于中间件的具体应用,后续的文章会说到。先说这里的路由分组。要给某个路由分组中定义的所有路由分配中间件,可以在定义分组之前使用middleware方法。中间件将会按照数组中定义的顺序依次执行:

    Route::middleware(['first', 'second'])->group(function () {
        Route::get('/', function () {
            // Uses first & second Middleware
        });
    
        Route::get('user/profile', function () {
            // Uses first & second Middleware
        });
    });
    
  • 命名空间
    路由分组另一个通用的例子是使用namespace方法分配同一个PHP命名空间给该分组下的多个控制器:

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

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

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

    Route::domain('{account}.blog.dev')->group(function () {
        Route::get('user/{id}', function ($account, $id) {
            return 'This is ' . $account . ' page of User ' . $id;
        });
    });
    
  • 路由前缀
    prefix方法可以用来为分组中每个路由添加一个给定URI前缀,例如,你可以为分组中所有路由URI添加admin前缀:

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

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

总结

到此,关于Lavavel中的路由基础部分就总结完毕!文中很大一部分的内容都参考了网站其它文章。还是那句话,路由非常重要;理解路由对于理解框架有着至关重要的帮助,Laravel是一个庞大的框架,我们需要通过基础的部分进行入手,先掌握招式,再修炼内功。

果冻想——一个原创技术文章分享网站。

2018年3月16日 于内蒙古包头。

未经允许不得转载:果冻想 » Laravel初级教程之路由
网站维护离不开您的支持,您可以赞助本站,谢谢支持
×

感谢您的支持,我们会一直保持!

扫码支持
请土豪扫码随意打赏

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

赞助本站
关注微信公众号
关注微信公众号和果冻一起分享你的疑惑与心得。
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

玩技术,我们是认真的

联系我们关于果冻