路由介绍和定义

一.路由介绍

路由的作用就是让 URL 地址更加的规范和优雅,或者说更加简洁;
设置路由对 URL 的检测、验证等一系列操作提供了极大的便利性;
在 ThinkPHP5.1 中,路由是默认开启的,没有配置开关,不需要手动配置;
创建一个 Address 控制器类,创建两个方法,具体如下:

  1. class Address extends Controller
  2. {
  3. public function index()
  4. {
  5. return 'index';
  6. }
  7. public function details($id)
  8. {
  9. return 'details 目前调用的 id:'.$id;
  10. }
  11. }

为了让我们路由的课程观看更加直观,我们采用内置服务器的方式来演示;
通过命令行模式键入到当前项目目录后输入命令:php think run 启动;
此时,public 目录会自动被绑定到顶级域名:127.0.0.1:8000 上;
我们只要在地址栏键入:http://localhost:8000 或(127.0.0.1:8000)即可;

二.路由定义

在没有定义路由规则的情况下,我们访问 address/details 包含 id 的 URL 为:
http://localhost:8000/address/details/id/5
//或者…/id/5.html
将这个 URL 定义路由规则,在根目录 route 下的 Route.php 里配置;
Route::get(‘details/:id’, ‘Address/details’);
当配置好路由规则后,会出现非法请求的错误,我们需要用路由规则的 URL 访问;
http://localhost:8000/details/5
//或者…/details/5.html
一般来说 GET 方法是用的最多的,所以我们使用 Route::get()最多,其它如下:
所有请求方式(快捷方式):GET(get)、POST(post)、DELETE(delete)、PUT(put)
PATCH(patch)、*(any,任意请求方式)
快捷方式,就是直接用 Route::get、Route::post 等方式即可,无须第三参数;
当我们设置了强制路由的时候,访问首页就会报错,必须强制设置首页路由;
开始强制路由,需要在 app.php 里面进行配置,然后配置首页路由;

  1. 'url_route_must'
  2. =>
  3. true,
  4. Route::get('/', 'index');
  5. //当写一个 index,表面控制器是 Index

在路由的规则表达式中,有多种地址的配置规则,具体如下:

  1. //静态路由
  2. Route::get('ad', 'address/index');
  3. //静态动态结合的地址
  4. Route::get('details/:id', 'address/details');
  5. //多参数静态动态结合的地址
  6. Route::get('search/:id/:uid', 'address/search');
  7. //全动态地址,不限制是否 search 固定
  8. Route::get(':search/:id/:uid', 'address/search');
  9. //包含可选参数的地址
  10. Route::get('find/:id/[:content]', 'address/find');
  11. //规则完全匹配的地址
  12. Route::get('search/:id/:uid$', 'address/search');
  13. //也可以开启全局完全匹配,在 app.php 中配置
  14. 'route_complete_match'
  15. => true,

路由定义好之后,我们在控制器要创建这个路由地址,可以通过 url()方法实现;

  1. //不定义标识的做法
  2. return url('address/details', ['id'=>10]);
  3. //定义标识的做法
  4. Route::get('details/:id', 'address/details')->name('det');
  5. return url('det', ['id'=>10]);

路由的变量规则和闭包

一.变量规则

系统默认的路由变量规则为\w+,即字母、数字和下划线;
如果我们需要对于具体的变量进行单独的规则设置,则需要通过 pattern()方法;
将 details 方法里的 id 传值,严格限制必须只能是数字\d+;
Route::get(‘details/:id’, ‘address/details’)
->name(‘det’)
->pattern(‘id’, ‘\d+’);
也可以设置 search 方法的两个值的规则,通过数组的方式传递参数;

  1. Route::get('search/:id/:uid', 'address/search')
  2. ->pattern([
  3. 'id'
  4. =>
  5. '\d+',
  6. 'uid'
  7. =>
  8. '\d+'
  9. ]);

以上两种,均为局部变量规则,也可以直接在 Route.php 设置全局变量规则;

  1. Route::pattern([
  2. 'id'
  3. =>
  4. '\d+',
  5. 'uid'
  6. =>
  7. '\d+'
  8. ]);

也支持使用组合变量规则方式,实现路由规则;
Route::get(‘details-‘, ‘address/details’)
->pattern(‘id’, ‘\d+’);
动态组合的拼装,地址和参数如果都是模糊动态的,可以使用如下方法;
Route::get(‘details-:name-:id’, ‘Hello_:name/details’)
->pattern(‘id’, ‘\d+’);
在不设定任何规则的情况下,系统默认为\w+,在配置文件中可以更改默认规则;
‘default_route_pattern’ => ‘[\w-]+’

二.闭包支持

闭包支持我们可以通过 URL 直接执行,而不需要通过控制器和方法;
Route::get(‘think’, function () {
return ‘hello,ThinkPHP5!’;
});
闭包支持也可以传递参数和动态规则;
Route::get(‘hello/:name’, function ($name) {
return ‘Hello,’ . $name;
});

路由的地址与缓存

一.路由地址

路由的地址一般为:控制器/方法,如果多模块则:模块/控制器/方法;

  1. //默认 Index 控制器
  2. Route::get('/', 'index');
  3. //控制器/方法
  4. Route::get('details/:id',
  5. 'Address/details');
  6. //模块/控制器/方法
  7. Route::get('details/:id',
  8. 'index/Address/details');

支持多级控制器,并且支持路由到相应的地址;

  1. //目录为:application\controller\group
  2. namespace app\controller\group;
  3. //地址为:application\controller\group
  4. http://localhost:8000/group.address/details/id/5
  5. //支持多级路由
  6. Route::get('details/:id', 'group.Address/details');

支持动态路由地址以及额外参数地址;
Route::get(‘details-:name-:id’, ‘Hello_:name/details’);
//获取隐式 GET 值:$this->request->param(‘flag’);
Route::get(‘details/:id’, ‘Address/details?flag=1&status=1’);
支持直接去执行方法,不单单是普通方法,还有静态方法;
Route::get(‘details/:id’, ‘app\controller\Address@details’);
Route::get(‘stat/:id’, ‘app\controller\Address::stat’);
路由也支持重定向功能,实现一个外部跳转;
Route::get(‘details/:id’,
http://www.liyanhui.com/details/:id')->status(**302**);
Route::redirect(‘details/:id’,
http://www.liyanhui.com/details/:id‘, 302);
路由也可以对模版进行传值;
Route::view(‘see/:name’,
‘See/other’);
Route::view(‘see/:name’,
‘See/other’,
[‘email’=>’huiye@163.com’]);

二.路由缓存

路由缓存可以极大的提高性能,需要在部署环境下才有效果,在 app.php 开启;
‘route_check_cache’
=> true,
为了测试路由缓存是否真的在起作用,可以通过一条命令行命令来清理缓存测试;
>php think clear —route

路由的参数和快捷路由

一.路由参数

设置路由的时候,可以设置第三个数组参数,主要实施匹配检测和行为执行;
ext 参数作用是检测 URL 后缀,比如:我们强制所有 URL 后缀为.html;
Route::get(‘details/:id’,
‘address/details’, [‘ext’=>’html’]);
…[‘ext’=>’html|shtml’]
//支持多个
第三数组参数也可以作为对象的方法存在,比如改下成如下形式;
Route::get(‘details/:id’, ‘address/details’)->ext(‘html’);
https 参数作用是检测是否为 https 请求,结合 ext 强制 html 如下;
Route::get(‘details/:id’, ‘address/details’, [‘ext’=>’html’, ‘https’=>true]);
Route::get(‘details/:id’, ‘address/details’)->ext(‘html’)->https();
如果想让全局统一配置 URL 后缀的话,可以在 app.php 中设置;
//设置 false 为禁止后缀,空允许所有后缀
‘url_html_suffix’
=> ‘html’,
denyExt 参数作用是禁止某些后缀的使用;
Route::get(‘details/:id’, ‘address/details’)->denyExt(‘gif|jpg|png’);
filter 参数作用是对额外参数进行检测;
Route::get(‘details/:id’, ‘address/details’)->filter(‘id’, 10);
model 参数作用是绑定到模型,第三参数设置 false 避免异常,也可以多参数;
Route::get(‘user/:id’, ‘address/getUser’)->model(‘id’, ‘\app\model\User’);
…->model(‘id’,
‘\app\model\User’,false);
Route::get(‘user/:id/:name’…->model(‘id&name’,
‘\app\model\User’);
option 参数作用是全局的路由进行配置,且可以多次调用;
Route::>option(‘ext’, ‘html’)->option(‘https’, true);

二.快捷路由

快捷路由可以快速给控制器注册路由,还可以更加不同的请求类型设置前缀;
Route::controller(‘short’, ‘Short’);
快捷路由控制器和方法的编写原则,给方法前面加上 get 或 post 等请求类型;

  1. class Short extends
  2. Controller
  3. {
  4. public function
  5. index()
  6. {
  7. return 'index';
  8. }
  9. public function getInfo()
  10. {
  11. return 'getInfo';
  12. }
  13. public function getList()
  14. {
  15. return 'getList';
  16. }
  17. public function postInfo()
  18. {
  19. return 'postInfo';
  20. }
  21. }

路由的分组与注解

一.路由分组

路由分组,即将相同前缀的路由合并分组,这样可以简化路由定义,提高匹配效率;
在定义分组路由前,我们专门做一个类,来实际演练这个效果;

  1. class Collect extends Controller
  2. {
  3. public function index()
  4. {
  5. return 'index';
  6. }
  7. public function read($id)
  8. {
  9. return 'read id:'.$id;
  10. }
  11. public function who($name)
  12. {
  13. return 'your name:'.$name;
  14. }
  15. }

使用 group()方法,来进行分组路由的注册;
Route::group(‘col’, [
‘:id’
=>
‘Collect/read’,
‘:name’
=>
‘Collect/who’
])->ext(‘html’)->pattern([‘id’=>’\d+$’, ‘name’=>’\w+$’]);
使用 group()方法,并采用闭包的形式进行注册;
Route::group(‘col’, function () {
Route::get(‘:id’, ‘Collect/read’);
Route::get(‘:name’, ‘Collect/who’);
})->ext(‘html’)->pattern([‘id’=>’\d+$’, ‘name’=>’\w+$’]);
使用 prefix()方法,简化路径的地址;
Route::group(‘col’,
function () {
Route::get(‘:id’, ‘read’);
Route::get(‘:name’, ‘who’);
}) ->prefix(‘Collect/‘)
->ext(‘html’)
->pattern([‘id’=>’\d+$’, ‘name’=>’\w+$’]);
使用 append()方法,可以额外传入参数,用 request 获取;
Route::group()…->append([‘flag’=>1]);
路由规则(主要是分组和域名路由)定义的文件,加载时会解析消耗较多的资源;
尤其是规则特别庞大的时候,延迟解析开启让你只有在匹配的时候才会注册解析;
我们在 app.php 中开启延迟解析,多复制几组规则,然后通过 trace 来查看内存;
‘url_lazy_route’
=> true,

二.注解路由

路由系统还提供了一个可以在注解(注释)中直接创建路由的方式,但默认关闭;
我们在 app.php 中,开启路由注解功能;
‘routeannotation’
=> true,
然后在控制器设置注解代码即可,可以使用 PHPDOC 生成一段,然后添加路由规则;
/
*
@param $id
*
@return string
*
@route(‘col/:id’);
*/
第二参数,可以设置请求类型,而需要设置更多的规则,可以换行设置;
/


*
@param $id
*
@return string
*
@route(‘col/:id’, ‘get’)

->ext(‘html’)

->pattern([‘id’=>’\d+’])

/
有几个注意点:语句结尾不需要分号,路由规则结束后,需要有一个空行;
支持资源路由,下节课会讲到具体资源路由;
/

*
@route_*(‘col’)
/
class Collect extends Controller

路由的MISS与跨域请求

一.MISS 路由

全局 MISS,类似开启强制路由功能,匹配不到相应规则时自动跳转到 MISS;
Route::miss(‘public/miss’);
分组 MISS,可以在分组中使用 miss 方法,当不满足匹配规则时跳转到这里;
Route::miss(‘miss’);

二.跨域请求

当不同域名进行跨域请求的时候,由于浏览器的安全限制,会被拦截;
所以,为了解除这个限制,我们通过路由 allowCrossDomain()来实现;
Route::get(‘col/:id’, ‘Collect/read’)
->ext(‘html’)->allowCrossDomain();
实现跨域比如没有实现的 header 头文件多了几条开头为 Access 的信息;
此时,这个页面,就可以支持跨域请求的操纵了;
我们创建一个不同端口号或不同域名的 ajax 按钮,点击获取这个路由页面信息;
如果,没有开启跨域请求,则会爆出提醒:
已拦截跨源请求:同源策略禁止读取位于 http://localhost:8000/col/5.html 的远程资源。(原因:CORS 头缺
少 ‘Access-Control-Allow-Origin’)
开启后,即正常获取得到的数据;
如果你想限制跨域请求的域名,则可以增加一条参数;
Route::get(‘col/:id’, ‘Collect/read’)
->ext(‘html’)
->header(‘Access-Control-Allow-Origin’,’http://localhost‘)
->allowCrossDomain();

路由的绑定与别名

一.路由绑定

路由绑定可以简化 URL 和路由规则的定义,可以绑定到模块/控制器/操作;
由于本身不是规则,需要关闭强制路由来测试,本身绑定并不是定义路由;
index 模块/User 控制器/read:http://.../index/user/read/id/5;
//绑定路由到 index 模块
Route::bind(‘index);
http://.../user/read/id/5
//绑定路由到 User 控制器
Route::bind(‘index/User);
http://.../read/id/5
//绑定路由到 read 操作
Route::bind(‘index/User/read);
http://.../id/5
当我们再创建一个 admin 模块,只要绑定到 admin 模块,开启路由就切换了;
Route::bind(‘admin’);
Route::get(‘user/:id’,’/user/read’);
//未绑定则:admin/user/read

二.路由别名

给一个控制器起一个别名,可以通过别名自动生成一系列规则;
比如,给 index 模块下的 User 控制器创建别名:user,省去了模块 index;
Route::alias(‘user’, ‘index/User’);
http://localhost:8000/user/create
http://localhost:8000/user/edit/id/5
http://localhost:8000/user/read/id/5
也可以直接绑定到类,来实现相同的效果;
Route::alias(‘user’, ‘\app\index\controller\User’);
也支持别名设置限定条件,比如 ext 等;
Route::alias(‘user’,
‘index/User’, [‘ext’=>’html’]);
Route::alias(‘user’,
‘index/User’)->ext(‘html’);
PS:这两个知识点,部分功能有些问题;而别名路由和前面的快捷路由在 PHP6 已经废
弃,产生的问题自然在新版也没了;

资源路由

资源路由,采用固定的常用方法来实现简化 URL 的功能;
系统提供了一个命令,方便开发者快速生成一个资源控制器;
php think make:controller index/Blog
模块/控制器,默认在 controller 目录下,根据你的情况调整路径结构;
php
think
make:controller
Blog
//单应用
php
think
make:controller
../index/controller/Blog
//多应用
模块/控制器,默认在 controller 目录下,根据你的情况调整路径结构;
从生成的多个方法,包含了显示、增删改查等多个操作方法;
在路由 route.php 文件下创建一个资源路由,资源名称可自定义;
Route::resource(‘blog’, ‘Blog’);
//多应用即:index/Blog
这里的 blog 表示资源规则名,Blog 表示路由的访问路径;
资源路由注册成功后,会自动提供以下方法,无须手动注册;
GET 访问模式下:index(blog),create(blog/create),read(blog/:id)
edit(blog/:id/edit)
POST 访问模式下:save(blog);
PUT 方式模式下:update(blog/:id);
DELETE 方式模式下:delete(blog/:id);
http://localhost:8000/blog/
(index)
http://localhost:8000/blog/5
(read)
http://localhost:8000/blog/5/edit
(edit)
对于 POST,是新增,一般是表单的 POST 提交,而 PUT 和 DELETE 用 AJAX 访问;
将跨域提交那个例子修改成.ajax,其中 type 设置为 DELETE 即可访问到;
$.ajax({
type : “DELETE”,
url : “http://localhost:8000/blog/10“,
success : function (res) {
console.log(res);
}
});
默认的参数采用 id 名称,如果你想别的,比如:blog_id,则:
->vars([‘blog’=>’blog_id’]);
//相应的 delete($blog_id)
也可以通过 only()方法限定系统提供的资源方法,比如:
->only([‘index’,’save’,’create’]) .
还可以通过 except()方法排除系统提供的资源方法,比如:
->except([‘read’,’delete’,’update’])
使用 rest()方法,更改系统给予的默认方法,1.请求方式;2.地址;3.操作;
Route::rest(‘create’, [‘GET’, ‘/:id/add’, ‘add’]);
//批量
Route::rest([
‘save’
=>
[‘POST’, ‘’, ‘store’],
‘update’
=>
[‘PUT’, ‘/:id’, ‘save’],
‘delete’
=>
[‘DELETE’, ‘/:id’, ‘destory’],
]);
使用嵌套资源路由,可以让上级资源对下级资源进行操作,创建 Comment 资源;
class Comment
{
public function read($id, $blog_id)
{
return ‘Comment id:’.$id.’,Blog
id:’.$blog_id;
}
public function edit($id, $blog_id)
{
return ‘Comment id:’.$id.’,Blog
id:’.$blog_id;
}
}
使用嵌套资源路由,可以让上级资源对下级资源进行操作,创建 Comment 资源;
Route::resource(‘blog.comment’, ‘Comment’);
资源嵌套生成的路由规则如下:
http://localhost:8000/blog/:blog_id/comment/:id
http://localhost:8000/blog/:blog_id/comment/:id/edit
嵌套资源生成的上级资源默认 id 为:blog_id,可以通过 vars 更改;
Route::resource(‘blog.comment’, ‘Comment’)
->vars([‘blog’=>’blogid’]);

域名的路由

一.域名路由

要使用域名路由,首先,在本地我们需要通过 hosts 文件来映射;
打开 C:\Windows\System32\drivers\etc 找到 hosts 文件;
在末尾添加一句:127.0.0.1 news.abc.com 映射二级域名;
再在末尾添加一句:127.0.0.1 a.news.abc.com 用于三级域名泛指;
此时,我们访问 news.abc.com 就直接映射到 localhost 里了;
如果想访问 thinkphp 独立的服务器,开启后,直接:8080 即可;
http://news.abc.com:8000
拿 Collect 控制器举例,复习一下路由的规则;
Route::get(‘edit/:id’, ‘Collect/edit’);
如果想限定在 news.abc.com 这个域名下才有效,通过域名路由闭包的形式;
Route::domain(‘news’, function () {
Route::get(‘edit/:id’, ‘Collect/edit’);
});
这里的 domain()即域名路由,第一参数,表示二级(子)域名的名称;
除了闭包方式,也可以通过数组的方式来设置域名路由;
Route::domain(‘news’, [
‘edit/:id’ => [‘Collect/edit’]
]);
除了二级(子)域名设置外,也可以设置完整域名;
Route::domain(‘news.abc.com’, [
‘edit/:id’ => [‘Collect/edit’]
]);
支持多个二级(子)域名,使用相同的路有规则;
Route::domain([‘news’, ‘blog’, ‘live’], function () {
Route::get(‘edit/:id’, ‘Collect/edit’);
});
可以作为方法,进行二级(子)域名的检测,或完整域名检测;
Route::get(‘edit/:id’, ‘Collect/edit’)->domain(‘news’);
Route::get(‘edit/:id’,
‘Collect/edit’)->domain(‘news.abc.com’);

二.域名绑定

在 app.php 中可以设置根域名,如果不设置,会默认自动获取;
‘url_domain_root’
=> ‘abc.com’,
当设置了根域名后,如果实际域名不符,将解析失败;
域名设置还支持绑定指定的模块,比如多应用的 admin 模块;
Route::domain(‘news’, ‘admin’);
Route::domain(‘news.abc.com’, ‘admin’);
Route::domain(‘127.0.0.1’, ‘admin’);
如果遇到三级域名,并且需要通用泛指,可以使用通配符;
Route::domain(‘
.news’, [
‘edit/:id’ => [‘Collect/edit’]
]);
而直接使用通配符,则指定所有的二级域名;
Route::domain(‘
‘,
[
‘edit/:id’ =>
[‘Collect/edit’]
]);
PS:还绑定到命名空间、类,额外参数、分组等操作和前面众多路由一样,不再重复

路由的URL生成

之前所有的 URL,都是手动键入的,而路由也提供了一套生成方法;
Url::build(‘地址表达式’,[‘参数’],[‘URL 后缀’],[‘域名’])
url(‘地址表达式’,[‘参数’],[‘URL 后缀’],[‘域名’])
在 Collect 演示生成,拿 Blog 来实现 URL 地址;
使用 build()方法,只传一个控制器时,会被误认为 Collect 下的 blog 方法;
Url::build(‘Blog’);
// /collect/blog.html
在没有设置路由的情况下,传递一个控制器以及操作方法;
Url::build(‘Blog/create’);
// /blog/create.html
如果设置了对应路由,第 4 条生成的 URL 会相应的改变;
Route::get(‘bc’, ‘Blog/create’);
//
/bc.html
Route::get(‘bl/cr’, ‘Blog/create’);
//
/bl/cr.html
下面是没有设置路由和设置路由的带参数的 URL 生成;
Url::build(‘Blog/read’, ‘id=5’);
//
/blog/read/id/5.html
//
/read/5.html
参数部分,也可以用数组的方式,当然,多参数也支持;
Url::build(‘Blog/read’,
[‘id’=>5]);
Url::build(‘Blog/read’,
‘id=5&uid=10’);
Url::build(‘Blog/read’,
[‘id’=>5, ‘uid’=>10]);
也可以使用助手函数 url 直接来设置;
url(‘Blog/read’, [‘id’=>5]);
也可以使用普通的地址来设置 url;
Url::build(‘Blog/read?id=5’);
也可以使用和路由规则配对的方式设置 url;
Url::build(‘/read/5’);
在 app.php 可以设置默认 html 后缀,也可以在方法第三个参数设置;
url(‘Blog/edit’, [‘id’=>5], ‘shtml’);
使用#name,可以生成一个带锚点的 url;
url(‘Blog/edit#name’, [‘id’=>5]);
使用 Url::root(‘/index.php’)在 URL 前面加上一个 index.php;
但这个添加需要整体考虑路径是否支持或正确,否则无法访问;
在本身有 index.php 的时候,使用 Url::root(‘/‘)隐藏;
Url::root(‘/index.php’);