## 定义路由
URL地址里面的`index`模块怎么才能省略呢,默认的URL地址显得有点长,下面就来说说如何通过路由简化URL访问。
我们在路由定义文件(`application/route.php`)里面添加一些路由规则,如下:
~~~
return [
// 添加路由规则 路由到 index控制器的hello操作方法
'hello/:name' => 'index/index/hello',
];
~~~
该路由规则表示所有`hello`开头的并且带参数的访问都会路由到`index`控制器的`hello`操作方法。
路由之前的URL访问地址为:
~~~
http://tp5.com/index/index/hello/name/thinkphp
~~~
定义路由后就只能访问下面的URL地址
~~~
http://tp5.com/hello/thinkphp
~~~
>[danger] #### 注意
>****
> 定义路由规则后,原来的URL地址将会失效,变成非法请求。
![](https://box.kancloud.cn/2016-09-07_57cf9c0f199fc.png)
但这里有一个小问题,如果我们只是访问
~~~
http://tp5.com/hello
~~~
将发生错误,
![](https://box.kancloud.cn/2016-07-13_578643933f2b0.png)
事实上这是由于路由没有正确匹配到,我们修改路由规则如下:
~~~
return [
// 路由参数name为可选
'hello/[:name]' => 'index/hello',
];
~~~
使用`[]`把路由规则中的变量包起来,就表示该变量为可选,接下来就可以正常访问了。
~~~
http://tp5.com/hello
~~~
当`name`参数没有传入值的时候,`hello`方法的`name`参数有默认值`World`,所以输出的内容为 `Hello,World!`
除了路由配置文件中定义之外,还可以采用动态定义路由规则的方式定义,例如在路由配置文件(`application/route.php`)的开头直接添加下面的方法:
~~~
use think\Route;
Route::rule('hello/:name', 'index/hello');
~~~
完成的效果和使用配置方式定义是一样的。
无论是配置方式还是通过Route类的方法定义路由,都统一放到路由配置文件`application/route.php`文件中,具体原因后面会揭晓。
>[success]#### 提示:
> * * * * *
>注意路由配置不支持在模块配置文件中设置。
### 完整匹配
前面定义的路由是只要以hello开头就能进行匹配,如果需要完整匹配,可以使用下面的定义:
~~~
return [
// 路由参数name为可选
'hello/[:name]$' => 'index/hello',
];
~~~
当路由规则以`$`结尾的时候就表示当前路由规则需要完整匹配。
当我们访问下面的URL地址的时候:
~~~
http://tp5.com/hello // 正确匹配
http://tp5.com/hello/thinkphp // 正确匹配
http://tp5.com/hello/thinkphp/val/value // 不会匹配
~~~
### 闭包定义
还支持通过定义闭包为某些特殊的场景定义路由规则,例如:
~~~
return [
// 定义闭包
'hello/[:name]' => function ($name) {
return 'Hello,' . $name . '!';
},
];
~~~
或者
~~~
use think\Route;
Route::rule('hello/:name', function ($name) {
return 'Hello,' . $name . '!';
});
~~~
>[success]#### 提示:
> * * * * *
> 闭包函数的参数就是路由规则中定义的变量。
因此,当访问下面的URL地址:
~~~
http://tp5.com/hello/thinkphp
~~~
会输出
~~~
Hello,thinkphp!
~~~
### 设置URL分隔符
如果需要改变URL地址中的`pathinfo`参数分隔符,只需要在应用配置文件(`application/config.php`)中设置:
~~~
// 设置pathinfo分隔符
'pathinfo_depr' => '-',
~~~
路由规则定义无需做任何改变,我们就可以访问下面的地址:
~~~
http://tp5.com/hello-thinkphp
~~~
### 路由参数
我们还可以约束路由规则的请求类型或者URL后缀之类的条件,例如:
~~~
return [
// 定义路由的请求类型和后缀
'hello/[:name]' => ['index/hello', ['method' => 'get', 'ext' => 'html']],
];
~~~
上面定义的路由规则限制了必须是`get`请求,而且后缀必须是`html`的,所以下面的访问地址:
~~~
http://tp5.com/hello // 无效
http://tp5.com/hello.html // 有效
http://tp5.com/hello/thinkphp // 无效
http://tp5.com/hello/thinkphp.html // 有效
~~~
> 更多的路由参数请参考完全开发手册的路由参数一节。
### 变量规则
接下来,我们来尝试一些复杂的路由规则定义满足不同的路由变量。在此之前,首先增加一个控制器类如下:
~~~
<?php
namespace app\index\controller;
class Blog
{
public function get($id)
{
return '查看id=' . $id . '的内容';
}
public function read($name)
{
return '查看name=' . $name . '的内容';
}
public function archive($year, $month)
{
return '查看' . $year . '/' . $month . '的归档内容';
}
}
~~~
添加如下路由规则:
~~~
return [
'blog/:year/:month' => ['blog/archive', ['method' => 'get'], ['year' => '\d{4}', 'month' => '\d{2}']],
'blog/:id' => ['blog/get', ['method' => 'get'], ['id' => '\d+']],
'blog/:name' => ['blog/read', ['method' => 'get'], ['name' => '\w+']],
];
~~~
在上面的路由规则中,我们对变量进行的规则约束,变量规则使用正则表达式进行定义。
我们看下几种URL访问的情况
~~~
// 访问id为5的内容
http://tp5.com/blog/5
// 访问name为thinkphp的内容
http://tp5.com/blog/thinkphp
// 访问2015年5月的归档内容
http://tp5.com/blog/2015/05
~~~
### 路由分组
上面的三个路由规则由于都是`blog`打头,所以我们可以做如下的简化:
~~~
return [
'[blog]' => [
':year/:month' => ['blog/archive', ['method' => 'get'], ['year' => '\d{4}', 'month' => '\d{2}']],
':id' => ['blog/get', ['method' => 'get'], ['id' => '\d+']],
':name' => ['blog/read', ['method' => 'get'], ['name' => '\w+']],
],
];
~~~
对于这种定义方式,我们称之为路由分组,路由分组一定程度上可以提高路由检测的效率。
### 复杂路由
有时候,我们还需要对URL做一些特殊的定制,例如如果要同时支持下面的访问地址
~~~
http://tp5.com/blog/thinkphp
http://tp5.com/blog-2015-05
~~~
我们只要稍微改变路由定义规则即可:
~~~
return [
'blog/:id' => ['blog/get', ['method' => 'get'], ['id' => '\d+']],
'blog/:name' => ['blog/read', ['method' => 'get'], ['name' => '\w+']],
'blog-<year>-<month>' => ['blog/archive', ['method' => 'get'], ['year' => '\d{4}', 'month' => '\d{2}']],
];
~~~
对 `blog-<year>-<month>` 这样的非正常规范,我们需要使用`<变量名>`这样的变量定义方式,而不是 `:变量名`方式。
简单起见,我们还可以把变量规则统一定义,例如:
~~~
return [
// 全局变量规则定义
'__pattern__' => [
'name' => '\w+',
'id' => '\d+',
'year' => '\d{4}',
'month' => '\d{2}',
],
// 路由规则定义
'blog/:id' => 'blog/get',
'blog/:name' => 'blog/read',
'blog-<year>-<month>' => 'blog/archive',
];
~~~
在`__pattern__`中定义的变量规则我们称之为全局变量规则,在路由规则里面定义的变量规则我们称之为局部变量规则,如果一个变量同时定义了全局规则和局部规则的话,当前的局部规则会覆盖全局规则的,例如:
~~~
return [
// 全局变量规则
'__pattern__' => [
'name' => '\w+',
'id' => '\d+',
'year' => '\d{4}',
'month' => '\d{2}',
],
'blog/:id' => 'blog/get',
// 定义了局部变量规则
'blog/:name' => ['blog/read', ['method' => 'get'], ['name' => '\w{5,}']],
'blog-<year>-<month>' => 'blog/archive',
];
~~~
>[danger]### 【 5.1 】使用须知
> * * * * *
> 5.1的路由配置文件改为`route/route.php`,并且支持随意命名,都会自动加载。并尽量使用方法注册路由的方式替代数组配置的方式,例如。
>
~~~
use think\facade\Route;
Route::get('blog/:id','blog/get');
Route::get('blog/:name','blog/read');
~~~
- 零、序言
- 一、基础
- (1)简介
- (2)安装
- (3)目录结构
- (4)运行环境
- (5)入口文件
- (6)资源访问
- (7)调试模式
- (8)控制器
- (9)视图
- (10)读取数据
- (11)总结
- 二、URL和路由
- (1)URL访问
- (2)参数传入
- (3)隐藏入口
- (4)定义路由
- (5)URL生成
- (6)总结
- 三、请求和响应
- (1)请求对象
- (2)请求信息
- (3)响应对象
- (4)总结
- 四、数据库
- (1)准备
- (2)数据库配置
- (3)原生查询
- (4)查询构造器
- (5)链式操作
- (6)事务支持
- 五、查询语言
- (1)查询表达式
- (2)批量查询
- (3)快捷查询
- (4)视图查询
- (5)闭包查询
- (6)获取值和列
- (7)聚合查询
- (8)时间查询
- (9)字符串查询
- (10)分块查询
- 六、模型和关联
- (1)模型定义
- (2)基础操作
- (3)读取器和修改器
- (4)类型转换和自动完成
- (5)查询范围
- (6)输入和验证
- (7)关联
- (8)模型输出
- 七、视图和模板
- (1)模板输出
- (2)分页输出
- (3)公共模板
- (4)模板定位
- (5)布局模板
- (6)标签定制
- (7)输出替换
- (8)渲染内容
- (9)助手函数
- 八、调试和日志
- (1)第一式:未雨绸缪——页面Trace
- (2)第二式:初见端倪——异常页面
- (3)第三式:拨云见日——断点调试
- (4)第四式:欲穷千里——日志分析
- (5)第五式:运筹帷幄——远程调试
- 九、API开发
- (1)API版本
- (2)异常处理
- (3)RESTFul
- (4)REST调试
- (5)API调试
- (6)安全建议
- 十、命令行工具
- (1)查看指令
- (2)模块生成
- (3)控制器生成
- (4)生成类库映射文件
- (5)生成路由缓存
- (6)生成字段缓存
- (7)指令扩展
- (8)命令行调试
- (9)命令行颜色支持
- (10)命令调用
- 十一、扩展
- (1)函数扩展
- (2)类库扩展
- (3)驱动扩展
- (4)Composer扩展
- 十二、杂项
- Session
- Cookie
- 验证码
- 文件上传
- 图像处理
- 单元测试
- 番外篇:学习ThinkPHP5的正确姿势
- 概念篇:ThinkPHP5名词解释
- 附录A、常见问题集
- 附录B、3.2和5.0区别
- 附录C、助手函数
- 附录D、5.1你必须努力避免的一些问题