## 定义路由 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'); ~~~