thinkphp-路由、路由的变量规则和闭包、地址和参数、域名和跨域请求
路由的定义
简介
路由的作用就是让URL 地址更加的规范和优雅,或者说更加简洁;
设置路由对URL 的检测、验证等一系列操作提供了极大的便利性;
路由是默认开启的,如果想要关闭路由,在config/app.php 配置;
// 是否启用路由
'with_route' => false,
路由的配置文件在config/route.php 中,配置文件作用是配置信息,定义文件在route/app.php,主要作用就是定义路由规则;
route 目录下的定义文件的文件名随机,都有效,或多个均有效果;
比如在route/app.php中书写规则
// Index控制器下的hello方法
Route::get('hello/:name', 'Index/hello');
对应的控制器中的方法是 controller/Index.php
public function hello($name = 'ThinkPHP6')
{
return 'hello,' . $name;
}
通过命令行模式键入到当前项目目录后输入命令:php think run 启动, 此时,public 目录会自动被绑定到顶级域名:127.0.0.1:8000 上;我们只要在地址栏键入:http://localhost:8000 或(127.0.0.1:8000)即可;本地可能会提示让你访问started On <http://0.0.0.0:8000/>,这时候不要理会这个,直接访问上面提到127地址即可。
路由定义
先创建一个控制器controller/Address.php
<?php
namespace app\controller;
class Address
{
public function index()
{
return 'index';
}
public function details($id)
{
return 'details 目前调用的id:'.$id;
}
}
在没有定义路由规则的情况下,我们访问address/details 包含id 的URL 为:
http://localhost:8000/address/details/id/5
或者http://localhost:8000/address/details/id/5.html [类似于静态的访问地址]
将这个URL 定义路由规则,在根目录route 下的app.php 里配置;
// Route::rule('地址(随意写)/:方法参数', '控制器/控制器的方法');
Route::rule('ds/:id', 'Address/details');
其中有Route::get Route::post Route::rule(get和post都支持),控制器首字母大小写均可,建议用大写语义更明确。
当路由配置好以后,源地址http://localhost:8000/address/details/id/5再访问就会提示非法请求的错误(不设置强制路由情况下,这个也应该可以正常访问),这时候就只能按照新的路由规则访问:
http://127.0.0.1:8000/ds/4 或者 http://127.0.0.1:8000/ds/4.html (4.php或者4.xml 都会整体当作参数传递,仅支持.html)
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
所有请求方式(快捷方式):GET(get)、POST(post)、DELETE(delete)、PUT(put)PATCH(patch)、*(any,任意请求方式) 默认是any
Route::get(...)、Route::post(...)、Route::delete(...)...
快捷方式,就是直接用Route::get、Route::post 等方式即可,无须第三参数;
地址栏一般都是get,不要用post
当我们设置了强制路由的时候,访问首页就会报错,必须强制设置首页路由;
开始强制路由,需要在app/route.php 里面进行配置,然后配置首页路由(默认是false);
'url_route_must' => true,
Route::rule('/', 'Index/index'); //反斜杠就是首页默认访问的地址
设置强制路由后,每一个控制器路径都需要设置路由才行,否则无法访问
访问http://127.0.0.1:8000/address/details/id/5,就会提示:当前访问路由未定义或不匹配
同样的可以更改首页指向的控制器
Route::rule('/', 'Test/index');
在路由的规则表达式中,有多种地址的配置规则(比较常用)
//静态路由
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');
路由定义好之后,我们在控制器要创建这个路由地址,可以通过url()方法实现
例如在控制器中,返回address/details/id/5 这个链接的路由地址:
不定义标识的做法
public function url()
{
return url('Address/details', ['id' => 5]);
}
访问这个方法就能获得:/ds/5.html 这个地址,即是路由地址。(通常这种地址用于模板中的链接)
如果没有设置对应的route规则,那么这个url方法会返回:/Address/details.html?id=5
定义标识的做法
public function url()
{
Route::get('ds/:id', 'Address/details', 'GET|POST')->name('ds');
return url('ds', ['id' => 5]);
}
就是如果在app/route.php中没有定义规则,那么就用上面这种方法,给路由定义一个名字->name,然后再返回。
一般都使用第一种方法。
路由的变量规则和闭包
变量规则
系统默认的路由变量规则为\w+,即字母、数字、中文和下划线;
如果你想更改默认的匹配规则,可以修改config/route.php 配置(一般不需要更改)
// 默认的路由变量规则
'default_route_pattern' => '[\w\.]+',
如果我们需要对于具体的变量进行单独的规则设置,则需要通过pattern()方法;
将details 方法里的id 传值,严格限制必须只能是数字\d+;
Route::get('ds/:id', 'Address/details')->pattern([
'id' => '\d+'
]);
这时候再访问
http://127.0.0.1:8000/ds/adas 直接报错
http://127.0.0.1:8000/ds/5adas 会将参数截断,5adas会只保留5,5.5也会只保留5
如果控制器方法中,需要传递多个参数,并分别设置不同的验证规则
控制器中
public function search($id, $uid)
{
return "详情-{$id}-{$uid}";
}
route/app.php
Route::get('ss/:id/:uid', 'Address/search')->pattern([
'id' => '\d+',
'uid' => '\d+'
]);
访问http://127.0.0.1:8000/ss/5/6 输出 详情-5-6
以上两种,均为局部变量规则,也可以直接在route/app.php 设置全局变量规则
// 在开头设置验证,那么其下面所有的路由都会按照这个规则验证
Route::pattern([
'id' => '\d+',
'uid' => '\d+'
]);
Route::get('ss/:id/:uid', 'Address/search');
此全局仅为本route/app.php的全局,并非整个系统的全局
也支持使用组合变量规则方式,实现路由规则
除了支持/:,还支持如下
Route::rule('ds-<id>', 'Address/details');
这时候访问地址就变成了:http://127.0.0.1:8000/ds-6,其中各种搭配随意组合,-也可以替换成_
动态组合的拼装,地址和参数如果都是模糊动态的,可以使用如下方法
比如,我有多个控制器文件,controller/Helloworld.php、Hellojs.php、Hellowu.php等,这时候就可以用动态控制器名
Route::rule('hi-<name>-<id>', 'Hello:name/index');
其中Hello:name ,Hellow是固定不变的字符串前缀,:name是动态变化的名称,而此名称就通过'hi-<name>-<id>中的<name>进行传递。如此,那么访问地址为:http://127.0.0.1:8000/hi-world-5或5.html,就访问到了Helloworld.php中的Index方法了。
Route::rule('hi/:name/:id', 'Hello:name/index');
闭包支持
闭包支持我们可以通过URL 直接执行,而不需要通过控制器和方法;只要执行了这个规则就会返回:
Route::get('think', function () {
return 'hello,ThinkPHP6!';
});
同样的也可以传递参数
Route::get('think/:name', function ($name) {
return "hello, {$name}";
});
路由的地址和参数
路由地址
路由的地址一般为:控制器/操作方法构成
//默认Index 控制器
Route::rule('/', 'index');
//控制器/操作方法
Route::rule('details/:id', 'Address/details');
支持多级控制器,并且支持路由到相应的地址;
//目录为: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');
对于地址,还有一种完整路径的方式去执行操作方法:完整类名@操作方法;
比如我创建一个静态方法
public static function details2($id)
{
return 'details 目前调用的id2:'.$id;
}
Route::rule('ds/:id', 'app\controller\Address@details2');
Route::rule('ds/:id', '\app\controller\Address@details2');
另一种静态方式:完整路径支持这种方法的路由地址:完整类名::静态方法
Route::rule('ds/:id', '\app\controller\Address::details2');
注意:静态方式只能调用静态方法,如果调用非静态方法就会报错!@方法无论方法是不是静态都可以调用!
路由可以通过::redirect()方法实现重定向跳转,第三参数为状态码;
Route::redirect('ds/:id', 'http://localhost/', 302);
路由参数
设置路由的时候,可以设置相关方法进行,从而实施匹配检测和行为执行
ext 方法作用是检测URL 后缀,比如:我们强制所有URL 后缀为.html;
Route::rule('details/:id', 'address/details')->ext('html');
Route::rule('details/:id', 'address/details')->ext('html|shtml');
强制让地址链接末尾检测是否有html,添加了->ext(html),那么{id}.html就不会整体作为参数传递了。此时,只有访问{id}.html才不会报错。
https 方法作用是检测是否为https 请求,结合ext 强制html 如下
Route::get('details/:id', 'address/details')->ext('html')->https();
如果想让全局统一配置URL 后缀的话,可以在config/route.php 中设置
具体值可以是单个或多个后缀,也可以是空字符串(任意后缀),false 禁止后缀
// URL伪静态后缀
'url_html_suffix' => 'html',
denyExt 方法作用是禁止某些后缀的使用,使用后直接报错,如下是禁止后缀为png和gif;
Route::rule('ds/:id', 'Address/details2')->denyExt('gif|png');
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'); // 简化的二级域名
如果验证失败那么就会报错。
ajax/pjax/json 方法作用是检测当前的页面是否是以上请求方式
Route::rule('ds/:id', 'Address/details')->ajax();
filter 方法作用是对额外参数进行检测,额外参数可表单提交post(严格看表单传递过来的参数是否匹配)
Route::rule('details/:id', 'address/details')->filter(['id'=>5, 'type'=>1]);
必须传递过来的参数是id=5 type=1的时候才能匹配到这个路由
append 方法作用是追加额外参数,这个额外参数并不需要通过URL 传递;
控制器中先写一个方法
public function details2($id, $status)
{
return 'details 目前调用的id2:'.$id . $status;
}
其中第二个参数,就用来接收append传递过来的额外的参数
// 追加一个参数
Route::rule('ds/:id', 'Address/details2')->append(['status' => 'a']);
如果你想统一配置多个参数,方便管理,可以使用option 方法数组配置;
Route::rule('ds/:id', 'Address/details')->option([
'ext' => 'html', // 必须是html
'https' => true // 必须是https请求
]);
路由的域名和跨域请求
域名路由
如果想限定在news.abc.com 这个域名下才有效,通过域名路由闭包的形式
Route::domain('news.abc.com', function() {
Route::rule('ds/:id', 'Address/details');
});
限定域名之后,使用localhost/ds/5就无法访问了,打开就会报错。
支持多个二级(子)域名开头部分,使用相同的路有规则
Route::domain(['news', 'blog', 'live'], function() {
Route::rule('ds/:id', 'Address/details');
});
可以作为方法,进行二级(子)域名开头部分的检测,或完整域名检测
Route::rule('details/:id', 'Address/details')->domain('news');
Route::rule('details/:id', 'Address/details')->domain('news.abc.com');
路由域名也支持:ext、pattern、append 等路由参数方法的操作
Route::domain(['news', 'blog', 'live'], function() {
Route::rule('ds/:id', 'Address/details');
})->ext('html');
即可以整体写,这些域名下的请求,后缀都使用->ext方法。
跨域请求
当不同域名进行跨域请求的时候,由于浏览器的安全限制,会被拦截
所以,为了解除这个限制,我们通过路由allowCrossDomain()来实现
Route::rule('details/:id', 'Address/details')->allowCrossDomain();
实现跨域比如没有实现的header 头文件多了几条开头为Access 的信息
如果你想限制跨域请求的域名,则可以增加一条参数
Route::rule('ds/:id', 'Address/details')
->allowCrossDomain([
// 只能是news.abc.com:8000 这个域名来取我的数据 仅对其开放
'Access-Control-Allow-Origin' => 'http://news.abc.com:8000'
]
);