路由的定义

路由简介

  1. 路由的作用就是让URL地址更加的规范和优雅,或者说更加简洁;
  2. 设置路由对URL的检测,验证等一系列操作提供了极大的便利性;
  3. 路由是默认开启的,如果想要关闭路由,在config/app.php配置;
// 是否启用路由
'with_route' => false, 
  1. 路由的配置文件在config/route.php中,定义文件在route/app.php;
  2. route 目录下的定义文件的文件名随机,都有效,或多个均有效果;
  3. 创建一个Address控制器类,创建两个方法,具体如下:
class Address
{
    public function index()
    {
        return 'index';
    }
    public function details($id)
    {
        return 'details 目前调用的 id:'.$id;
    }
}
  1. 为了让我们路由的课程观看更加直观,我们采用内置服务器的方式来演示;
  2. 通过命令行模式键入到当前项目目录后输入命令php think run启动;
  3. 此时public目录会自动被绑定到顶级域名127.0.0.1:8000上;
  4. 我们只要在地址栏键入http://localhost:8000127.0.0.1:8000即可;

路由定义

  1. 在没有定义路由规则的情况下,我们访问address/details包含id的URL为:
http://localhost:8000/address/details/id/5 //或者.../id/5.html
  1. 将这个URL定义路由规则,在根目录route/app.php里配置;
Route::rule('details/:id', 'Address/details');
  1. 当配置好路由规则后,会出现非法请求的错误,我们需要用路由规则的URL访问;
http://localhost:8000/details/5 //或者.../details/5.html

QQ截图20200731135748.png

  1. rule()方法是默认请求是any,即任何请求类型均可,第三参数可以限制:
Route::rule('details/:id', 'Address/xxx, 'GET'); //GET
Route::rule('details/:id', 'Address/xxx, 'POST'); //POST
Route::rule('details/:id', 'Address/xxx, 'GET|POST'); //GET 或 POST
  1. 所有请求方式(快捷方式):GET(get),POST(post),DELETE(delete),PUT(put),PATCH(patch),\*(any,任意请求方式)
Route::get(...)
Route::post(...)
Route::delete(...)... 
  1. 快捷方式,就是直接用Route::get,Route::post等方式即可,无须第三参数;
  2. 当我们设置了强制路由的时候,访问首页就会报错,必须强制设置首页路由;
  3. 开始强制路由,需要在route.php里面进行配置,然后配置首页路由;
// route.php
'url_route_must' => true,

// app.php
Route::rule('/', 'Index/index'); //反斜杠就是首页默认访问的地址

QQ截图20200731140057.png

  1. 在路由的规则表达式中,有多种地址的配置规则,具体如下:
//静态路由
Route::rule('ad', 'Address/index');
//静态动态结合的地址
Route::rule('details/:id', 'Address/details');
//多参数静态动态结合的地址
Route::rule('search/:id/:uid', 'Address/search');
//全动态地址,不限制是否 search 固定
Route::rule(':search/:id/:uid', 'Address/search');
//包含可选参数的地址
Route::rule('find/:id/[:content]', 'Address/find');
//规则完全匹配的地址
Route::rule('search/:id/:uid$', 'Address/search');
  1. 路由定义好之后,我们在控制器要创建这个路由地址,可以通过url()方法实现;
//不定义标识的做法
return url('Address/details', ['id'=>10]);

//定义标识的做法
Route::rule('details/:id', 'Address/details')->name('det');
return url('det', ['id'=>10]);

QQ截图20200731141203.png

路由的变量规则和闭包

变量规则

  1. 系统默认的路由变量规则为[\w\.]+,即字母,数字,中文和下划线和\.;
  2. 如果你想更改默认的匹配规则,可以修改config/route.php配置;
// 默认的路由变量规则
'default_route_pattern' => '[\w\.]+', 
  1. 如果我们需要对于具体的变量进行单独的规则设置,则需要通过pattern()方法;
  2. details方法里的id传值,严格限制必须只能是数字\d+;
Route::rule('details/:id', 'Address/details')->pattern(['id'=>'\d+']);

QQ截图20200731142112.png

  1. 也可以设置search方法的两个值的规则,通过数组的方式传递参数;
Route::rule('search/:id/:uid', 'Address/search')->pattern(['id' => '\d+','uid' => '\d+']);
  1. 以上两种,均为局部变量规则,也可以直接在app.php设置全局变量规则;
Route::pattern(['id' => '\d+','uid' => '\d+']);
  1. 也支持使用组合变量规则方式,实现路由规则;
Route::rule('details-<id>', 'address/details')->pattern('id', '\d+');

QQ截图20200731142247.png

  1. 动态组合的拼装,地址和参数如果都是模糊动态的,可以使用如下方法;
Route::rule('details-:name-:id', 'Hello:name/index')->pattern('id', '\d+');

闭包支持

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

路由的地址和参数

路由地址

  1. 路由的地址一般为:控制器/操作方法构成;
//默认 Index 控制器
Route::rule('/', 'index');
//控制器/操作方法
Route::rule('details/:id', 'Address/details');
  1. 支持多级控制器,并且支持路由到相应的地址;
//目录为:app\controller\group
namespace app\controller\group;
//地址为:app\controller\group
http://localhost:8000/group.blog/details/id/5
//支持多级路由
Route::rule('details/:id', 'group.Blog/details');

QQ截图20200731143159.png

  1. 对于地址,还有一种完整路径的方式去执行操作方法:完整类名@操作方法;
  2. 另一种静态方式:完整路径支持这种方法的路由地址:完整类名::静态方法;
Route::rule('ds/:id', '\app\controller\Address@details');

QQ截图20200731143524.png

  1. 路由可以通过::redirect()方法实现重定向跳转,第三参数为状态码;
Route::redirect('ds/:id', 'http://localhost/', 302);

路由参数

  1. 设置路由的时候,可以设置相关方法进行,从而实施匹配检测和行为执行;
  2. ext方法作用是检测URL后缀,比如:我们强制所有URL后缀为.html;
Route::rule('details/:id', 'address/details')->ext('html');
Route::rule('details/:id', 'address/details')->ext('html|shtml');

QQ截图20200731143623.png

  1. https方法作用是检测是否为https请求,结合ext强制html如下;
Route::get('details/:id', 'address/details')->ext('html')->https();
  1. 如果想让全局统一配置URL后缀的话,可以在config/route.php中设置;
  2. 具体值可以是单个或多个后缀,也可以是空字符串(任意后缀),false禁止后缀;
//设置 false 为禁止后缀,空允许所有后缀
'url_html_suffix' => 'html', 

QQ截图20200731144306.png

  1. denyExt 方法作用是禁止某些后缀的使用,使用后直接报错;
Route::rule('details/:id', 'address/details')->denyExt('gif|jpg|png');

QQ截图20200731144352.png

  1. domain方法作用是检测当前的域名是否匹配,完整域名和子域名均可;
Route::rule('ds/:id', 'Address/details')->domain('localhost');
Route::rule('ds/:id', 'Address/details')->domain('news.abc.com');
Route::rule('ds/:id', 'Address/details')->domain('news');

QQ截图20200731144610.png

  1. ajax/pjax/json方法作用是检测当前的页面是否是以上请求方式;
Route::rule('ds/:id', 'Address/details')->ajax();
  1. filter方法作用是对额外参数进行检测,额外参数可表单提交;
Route::rule('details/:id', 'address/details')->filter(['id'=>5, 'type'=>1]);

QQ截图20200731145450.png

  1. append方法作用是追加额外参数,这个额外参数并不需要通过URL传递;
Route::rule('details/:id', 'address/details')->append(['status'=>1]);

QQ截图20200731145618.png

  1. 如果你想统一配置多个参数,方便管理,可以使用option方法数组配置;
Route::rule('ds/:id', 'Address/details')->option(['ext' => 'html','https' => true]);

路由的域名和跨域请求

域名路由

  1. 要使用域名路由,首先,在本地我们需要通过hosts文件来映射;
  2. 打开C:\Windows\System32\drivers\etc\hosts文件;
  3. 在末尾添加一行127.0.0.1 tp6.1997sty.com映射二级域名;
  4. 此时,我们访问tp6.1997sty.com就直接访问框架了;
  5. 如果想访问thinkphp独立的服务器,开启后,直接:8000即可;
  • http://tp6.1997sty.com:8000
  1. 如果想限定在tp6.1997sty.com这个域名下才有效,通过域名路由闭包的形式;
Route::domain('tp6', function () {
Route::rule('details/:id', 'Address/details');
});

QQ截图20200731151206.png

  1. 除了二级(子)域名的开头部分,也可以设置完整域名;
Route::domain('tp6.1997sty.com', function () {
Route::rule('details/:id', 'Address/details');
});

QQ截图20200731151406.png

  1. 支持多个二级(子)域名开头部分,使用相同的路有规则;
Route::domain(['news', 'blog', 'live'], function () {
Route::rule('details/:id', 'Address/details');
});

QQ截图20200731151647.png

  1. 可以作为方法,进行二级(子)域名开头部分的检测,或完整域名检测;
Route::rule('details/:id', 'Address/details')->domain('tp6');
Route::rule('details/:id', 'Address/details')->domain('tp6.1997sty.com');
  1. 路由域名也支持:ext,pattern,append等路由参数方法的操作;

跨域请求

  1. 当不同域名进行跨域请求的时候,由于浏览器的安全限制,会被拦截;
  2. 所以,为了解除这个限制,我们通过路由allowCrossDomain()来实现;
Route::rule('details/:id', 'Address/details')->allowCrossDomain();
  1. 实现跨域比如没有实现的header头文件多了几条开头为Access的信息;
  2. 此时,这个页面,就可以支持跨域请求的操纵了;
  3. 我们创建一个不同端口号或不同域名的ajax按钮,点击获取这个路由页面信息;
  4. 如果,没有开启跨域请求,则会报错:
已拦截跨源请求:同源策略禁止读取位于 http://localhost:8000/details/5.html 的远程资源.(原因:CORS 头缺少 'Access-Control-Allow-Origin')
  1. 开启后,即正常获取得到的数据;
  2. 如果你想限制跨域请求的域名,则可以增加一条参数,仅允许访问该参数指定的域名;
Route::rule('col/:id', 'Collect/read')->allowCrossDomain(['Access-Control-Allow-Origin' => 'http://tp6.1997sty.com:8000']);

路由的分组和MISS

路由分组

  1. 路由分组,即将相同前缀的路由合并分组,这样可以简化路由定义,提高匹配效率;
  2. 使用group()方法,来进行分组路由的注册;
Route::group('address', function () {
    Route::rule(':id', 'Address/details');
    Route::rule(':name', 'Address/search');
})->ext('html')->pattern(['id'=>'\d+', 'name'=>'\w+']);

QQ截图20200731153401.png

  1. 也可以省去第一参数,让分组路由更灵活一些;
Route::group(function () {
    Route::rule('ds/:id', 'Address/details');
    Route::rule('sr/:name', 'Address/search');
})->ext('html')->pattern(['id'=>'\d+', 'name'=>'\w+']);
  1. 使用prefix()方法,可以省略掉分组地址里的控制器;
Route::group('address', function () {
    Route::rule(':id', 'details');
    Route::rule(':name', 'search');
})->ext('html')->prefix('Address/')->pattern(['id'=>'\d+', 'name'=>'\w+']);
  1. 使用append()方法,可以额外传入参数;
Route::group()...->append(['status'=>1]);
  1. 路由规则(主要是分组和域名路由)定义的文件,加载时会解析消耗较多的资源;
  2. 尤其是规则特别庞大的时候,延迟解析开启让你只有在匹配的时候才会注册解析;
  3. 我们在route.php中开启延迟解析,多复制几组规则,然后来查看内存占用;
'url_lazy_route' => true,

MISS 路由

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

QQ截图20200731153856.png

资源路由

资源路由

  1. 资源路由,采用固定的常用方法来实现简化URL的功能;
Route::resource('ads', 'Address');

QQ截图20200731160838.png

  1. 系统提供了一个命令,方便开发者快速生成一个资源控制器;
php think make:controller Blog

QQ截图20200731160421.png

  1. 从生成的多个方法,包含了显示,增删改查等多个操作方法;
  2. 在路由定义文件下创建一个资源路由,资源名称可自定义;
Route::resource('blog', 'Blog');

QQ截图20200731160921.png

  1. 这里的blog表示资源规则名,Blog表示路由的访问路径;
  2. 资源路由注册成功后,会自动提供以下方法,无须手动注册;
  3. GET 访问模式下:index(blog),create(blog/create),read(blog/:id),edit(blog/:id/edit)
  4. POST 访问模式下:save(blog);
  5. PUT 方式模式下:update(blog/:id);
  6. DELETE 方式模式下:delete(blog/:id);
http://localhost:8000/blog/ (index)
http://localhost:8000/blog/5 (read)
http://localhost:8000/blog/5/edit (edit)
  1. 对于POST,是新增,一般是表单的POST提交,而PUT和DELETE用AJAX访问;
  2. 将跨域提交那个例子修改成.ajax,其中type设置为DELETE即可访问到;
$.ajax({
    type : "DELETE",
    url : "http://localhost:8000/blog/10",
    success : function (res) {
        console.log(res);
    }
});
  1. 默认的参数采用id名称,如果你想别的,比如:blog_id,则:
->vars(['blog'=>'blog_id']); //相应的 delete($blog_id)
  1. 也可以通过only()方法限定系统提供的资源方法,比如:
->only(['index','save','create']);
  1. 还可以通过except()方法排除系统提供的资源方法,比如:
->except(['read','delete','update']);
  1. 使用rest()方法,更改系统给予的默认方法,1.请求方式;2.地址;3.操作;
Route::rest('create', ['GET', '/:id/add', 'add']);
//批量
Route::rest([
    'save' => ['POST', '', 'store'],
    'update' => ['PUT', '/:id', 'save'],
    'delete' => ['DELETE', '/:id', 'destory'],
]);
  1. 使用嵌套资源路由,可以让上级资源对下级资源进行操作,创建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;
    }
}
  1. 使用嵌套资源路由,可以让上级资源对下级资源进行操作,创建Comment资源;
Route::resource('blog.comment', 'Comment');
  1. 资源嵌套生成的路由规则如下:
http://localhost:8000/blog/:blog_id/comment/:id
http://localhost:8000/blog/:blog_id/comment/:id/edit
  1. 嵌套资源生成的上级资源默认id为:blog_id,可以通过vars更改;
Route::resource('blog.comment', 'Comment')->vars(['blog'=>'blogid']);

注解路由和URL生成

注解路由

  1. 路由的注解方式,并非系统默认支持,而是可选方案,需要额外安装扩展;
  2. 继续扩展安装,执行一下命令安装即可;
composer require topthink/think-annotation
  1. 安装好后,使用use引入相关类库;
use think\annotation\Route;
  1. 然后在控制器设置注解代码即可,可以使用PHPDOC生成一段,然后添加路由规则;
  2. 注意:这里必须使用双引号,单引号会直接报错;
/**
* @param $id
* @return string
* @route("details/:id");
*/
  1. 第二或以上参数,可以设置请求类型,比如要求是GET模式访问;
* @route("ds/:id", method="GET")
  1. 更多参数可实现更多功能(不需要考虑顺序),比如ext,https等;
* @route("ds/:id", method="GET", ext="html", https=1) //布尔值 0,1 代替
  1. 注解模式也支持资源路由,先要use相关类库,然后声明;
use think\annotation\Route\Resource;
/**
* @Resource("blog") */
class Blog ...
  1. 注解模式也支持分组,先要use相关类库,然后声明;
use think\annotation\Route;
use think\annotation\route\Group;
* @Group("ads")

URL生成

  1. 首先,创建一个新的控制器:Url.class,创建一个路由方法和URL生成的方法;
  2. 然后,路由这两个方法,具体如下:
Route::rule('ds', 'Url/index');
Route::rule('ds/:id', 'Url/details');
  1. 使用Route::buildUrl('地址', [参数]...)方式来获取路由的URL地址;
return Route::buildUrl('Url/details', ['id'=>5]);
  1. 注意:这里的地址和路由的定义是相辅相成的,如果没有定义,地址将会变化;
  2. 也可以给路由定义取一个别名,然后在生成URL的时候,直接使用这个别名调用;
Route::rule('ds/:id', 'Url/details')->name('u');
return Route::buildUrl('u', ['id'=>5]);
  1. 也可以直接使用路由地址生成URL,但这个方式并不需要和路由定义相匹配;
return Route::buildUrl('ds/5');
  1. 由于,我们默认在配置设置了后缀为.html,所以,生成的URL会自动加上;
return Route::buildUrl('ds/5')->suffix('shtml');
  1. 如果,你想添加完整域名路径,可以再添加domain方法;
return Route::buildUrl('ds/5')->domain(true);
return Route::buildUrl('ds/5')->domain('news');
return Route::buildUrl('ds/5')->domain('news.abc.com');
return Route::buildUrl('ds/5@news.abc.com');
  1. 也可以直接使用助手函数url()来代替Route::buildUrl();
return url('ds/5');