学习 laravel 必须要学习其路由,路由是 laravel 的特色,更是一个重中之重。是体验 laravel 优雅和美妙的第一站。
此路由非彼路由,不要和路由器的路由搞混淆了,虽然他们都有着分发请求的作用。
在这里,路由是指分析来自客户端请求的统一资源标识符(URI),根据设定的规则将请求分发至期待的处理逻辑,这一规则就是路由规则,而这一过程就是路由。
假设我们有这样一段简单的处理逻辑:
echo 'hello, world';
我希望通过 URL http://yourdomain/host
访问到这段处理逻辑,我们的路由规则就应该是/host
,该规则接受的请求类型是 GET
。如何在 laravel 内实现呢?我们通过编辑 laravel 框架目录下的app/Http/routes.php,添加以下代码:
Route::get('host', function() { echo 'hello, world'; });
就实现了我们之前所想的那样。通过这样一段简单的示例,我们至少应该明白路由是干啥的,其实就是用来匹配请求地址的。很多人不习惯是由于之前的框架已经给你制定好了一套规则,而现在,这个选择权全在于你,你拥有定制规则的最高权限。所以,这不是麻烦,而是更加灵活。让我们继续深入了解,你会爱上他的。
综述
laravel 的路由给了我们更多定制规则的理由。我开始并不习惯这样,我是一个从 ThinkPHP 转过来的初学者,习惯了 ThinkPHP 的默认路由规则,http://yourdomain/Module/Controller/Action
,这样的路由规则让你只需要去写控制器就行了,如果还需要定制或精简,可以通过配置文件调整和修改路由规则。
虽然承认 TP 这种框架和其他同类框架依旧可以同归配置实现同样的灵活的路由规则,但是,不可避免的事,就是你需要在他的规则体系下安排控制器、模型,谁都知道,这些控制器的基类杂糅了一堆来自其他类的方法,高度耦合,严重的增加了额外开销,扩展性并不是很好或者扩展过于麻烦。
相反,如果你只是简单的一个程序,laravel 则可以通过灵活的路由定制,创建一个简单而富有活力的程序,甚至不需要创建一个标准的控制器!
Laravel 的控制器为什么不类似于 TP 之流的框架呢?因为 laravel 的控制器是为了组织一类行为的,或针对某一资源建立一个标准的资源控制器。而 TP、CI 之流控制器的意义变得更为重要,是整个框架中实现逻辑的主要成分。Laravel 实现主要逻辑的可以是一系列类库,简单的逻辑甚至直接可以在路由实现,而控制器仅仅是一种实现方式之一。Laravel 这种设计在复杂项目中更为科学,使得分层系统得以十分容易的实现。
必须要知道的几件事
学习 laravel 的路由,有一样基础绝对不能丢—— HTTP 协议基础。不要求完全了解 HTTP 协议,但必须要知道一小部分概念。如果对其不了解,会在阅读 laravel 文档时出现很多疑惑。我在这里简单讲一部分。
Http 请求的流程如上图,客户端发送 HTTP 请求报文至服务器,服务器响应相应的请求。
客户端请求有很多种方法,常见的有 GET
,POST
。通常而言,我们在浏览器通过输入网址回车,都是以 GET
的方式请求数据,而通过表单提交,一般都是以 POST
方式提交。对于请求方法,在没有学习 laravel 之前我也只停留在这个层面,但是现在,你必须要知道除了 GET,POST 之外,还有 PUT
、DELETE
等等。
除了请求地址,还有请求主机和资源,请求主机一般是完整域名和 IP 地址,如 www.a.com
或142.53.75.112
,资源其实是一个合法的统一资源标识符(URI),相对于服务受理程序的目录,如 /index.php
,/article/1
。
以上部分都算是 HTTP 协议中请求部分的请求头,如果你是通过 POST、PUT 方法请求,还会包含请求体,请求体内是具体的数据。
大家应该去了解一下 RESTful,这是一种设计思想,这对学习 laravel 的路由有很大的帮助,尤其是在学习 laravel 控制器的资源控制器部分,很多人的疑惑都是在不了解 RESTful 的情况下产生的。阮一峰的日志中有两篇详细讲解了 RESTful,本人就不再班门弄斧,其中一篇的传送门在此给出:http://www.ruanyifeng.com/blog/2011/09/restful.html
正式开始了解 laravel 的路由
以下文章默认认为读者已经大致了解 RESTful 和 HTTP 协议,期间出现的名词不再注解。
Laravel 的路由灵活的确在某一程度上麻烦了,但我所了解的,这个麻烦绝对不是浪费时间,反而节约了大部分开发时间,并且完美提升了开发效率。
我们定义一下路由:
Route::get('/', function() { return view('index'); });
意味着我们访问 http://yourdoamin/
会显示渲染后的视图文件 index 的内容。这对于制作一个网站首页而言,十分简明,不需要再额外创建控制器。当然,如果你的程序中,显示首页是一类组织方法中的一部分,也可以用控制器实现,关于控制器我会在后面说到。
假如我想通过地址 http://yourdomain/about
访问到我博客的关于页面,该页面在视图about
文件内定义的,该如何定义路由?
Route::get('about', function() { return view('about'); });
那么现在我的博客有一堆文章,我想通过地址 http://yourdomain/article/1
访问 id 为 1 的文章,通过 http://yourdomain/article/2
访问 id 为 2 的文章怎么办?
Route::get('article/{id}', function($id) { return 'Article:' . $id; });
但是,我们都知道,大多数情况下,id 只能是数字,如何才能保证我们取到的只可以数字?而其他的则会被忽略?这样定义即可:
Route::get('article/{id}', function($id) { return 'Article:' . $id; })->where('id', '[0-9]+');
这样定义的话,如果输入的地址是 http://yourdomain/article/a
则不会被匹配至该路由。我们可以很容易看得出,这是通过正则制定的规则,也就是说,我们可以根据情况来制定需要的匹配规则。
但是,假如有这样一种情况,有很多地方都需要 id 作为参数,id 大都是这种数字,我们肯定不希望每一个路由规则都要写一次 where 方法来设置 id 的匹配规则。这时候可以通过这样一个方法来实现:
Route::pattern('id', '[0-9]+');
这样的话,每一个路由规则内出现 {id}
,都会以该规则去匹配。Laravel5 官方文档中建议通过在RouteServiceProvider
中的 boot
方法里定义上述内容,具体方法移步官方文档。
读到这里,应该对创建一个简单路由有所概念。本文不会全面罗列官方文档中所有内容,只是在容易犯迷糊的地方针对性详细讲解。建议多去阅读官方文档,并尝试里面给出的例子。要知道去尝试的时候你的电脑和服务器不会炸裂。
除了通过 Route::get()
定义一个匹配GET请求的路由还可以定义处理 POST、PUT、DELETE 的路由,分别是 Route::post()
,Route::put()
,Route::delete()
。我所了解的大多数浏览器的表单 form
仅支持 GET
和 POST
,那么如何实现另外两个呢?
一种是通过 ajax 实现,因为本质上浏览器是支持其他请求方法的。但是有时候一些项目只是想通过表单实现,官方文档提供了另一种解决方案,就是 方法欺骗
,可以参考国内一个翻译了的文档,给出传送门 http://laravel-china.org/docs/5.0/routing#method-spoofing.
运用好路由,可以写出优雅的接口,这对于 App 后端开发相当有用。遵循 RESTful,会让你的程序更加规范。