URL - 实现伪静态 ¶
作者:KK
发表日期:2016.12.10
为何要伪装URL ¶
http://xxx.com/?r=user/info
这样的URL会暴露程序设计的细节,比如让懂得MVC WEB开发的访问用户了解到我们是使用user控制器的info方法来实现的
然后他们可能会恶意地篡改成http://xxx.com/?r=user/into23xx
这样的地址再访问一下,由于找不到 into23xx
这个方法,导致程序报错,产生报错日志…
而报错页面又可能会把文件路径、服务器信息等内容暴露出去等等问题,所以,我们就希望在URL能掩盖程序的设计
比如伪装成“http://xxx.com/u123.html”这个网址就是调用 user控制器的info方法输出123这个用户的信息,又比如伪装成“http://xxx.com/n223.html ”这样的网址来调用news控制器的某个方法来输出223号新闻的内容
这种伪装的URL在业内一般都称之为伪静态
,表面上是静态的页面的址,指向一个html页面,实际上它是动态的数据输出
实现伪静态URL ¶
这是通过urlManager
(URL管理者)这个组件来实现的,你可以先在控制器里var_dump一下Yii::$app->urlManager
这个组件,它是Yii的核心组件
框架默认情况下是没有开启伪静态URL的,我们需要修改一下urlManager组件的配置来开启伪静态
在配置里增加urlManager
组件的配置,注意值是一个数组哦!因为我们要控制一些组件属性的值嘛
至于这个组件都有什么属性呢,详细需要参考官方的urlManager组件的对应类的说明yii\web\UrlManager
而咱们要实现伪静态只需要知道几个属性:enablePrettyUrl
、showScriptName
、enableStrictParsing
、rules
这四个属性!
请按照我下面这样来配置urlManager组件:
'urlManager' => [
'enablePrettyUrl' => true, //开启伪静态URL模式
'showScriptName' => false, //生成的网址里不带入口脚本名称
'enableStrictParsing' => true, //开启严格伪静态模式
'rules' => [
//伪静态规则配置,下面会讲解如何填写
],
],
好了,估计 ?r=test/abc
这样的URL一旦访问时就会找不到页面而报404错误了,说明已经成功开启了伪静态模式
接下来我们添加一个URL白名单让它路由到test控制器的abc方法
上面增加urlManager组件的配置后,里面有个rules属性,值是一个数组,这里就是放URL白名单的地方了
比如我们要实现/uiui.html
这个网址访问到test控制器的abc方法,就这样添加rules内容:
'rules' => [
'uiui.html' => 'test/abc',
],
神奇的事发生了!当你在浏览器输入“**http://xxx.com/uiui.html” 就会运行test控制器abc方法的代码
你又学会一招办法来实现这么高大上的偷天换日效果了,瞬间感觉你变得强大了好多,明天即可当上CTO,迎娶白富美了!!!......(路子还远呐亲)
然后你试着在控制器里echo Url::to(['test/abc']);
也会输出“/uiui.html” 这个结果!
再来,你在rules里面将规则改成'baba.html' => 'test/abc'
那Url::to方法也会将“test/abc”这个控制器方法标记生成为“/baba.html”
这就是为什么不提倡直接将网址写死在模板上的原因了,因为伪静态规则可能会在配置里被改变的,我们应该尽可能用Url::to来生成网址,减少维护的修改量
在伪静态中传递GET参数 ¶
我们用/uiui.html
这样的伪静态来取代了/?r=test/abc
的网址形式
那么又如何表达/?r=test/abc&userId=123
呢?难道是/uiui123.html
这样吗?不行不行
其实简单地做,就可以这样写:/uiui.html?userId=123
,这样控制器里依然可以收到参数,不信你试试 Yii::$app->request->get('userId')
但一般情况下我们项目中都尽量把GET参数也隐藏在伪静态之中,比如实现
/uiui7788.html
就相当于/?r=test/abc&userId=7788
的效果,配置办法如下:
'rules' => [
'uiui<userId:\d+>.html' => 'test/abc',
],
然后你试试
echo Url::to(['test/abc', 'userId' => 7788]);
就能看到输出/uiui7788.html
了
rules的key写法简介 ¶
这里需要一些正则表达式的知识基础,反正里面就是增加<
和>
这两个符号,表达这块区域要套一个参数进来
然后以参数的名称加:
号开头,比如userId:
这样Url::to方法的'userId' => 值
才能知道它要生成到伪静态的哪个位置上
而:
号后面的\d+
表示当user_id的值是数字的时候才可以生成,否则的话,比如'userId' => 'abc'
这样的参数放在to方法里
由于值是字符串abc而不是一个数字,所以无法跟rules里的\d+
(数字)匹配,不会生成预想中的/uiuiabc.html
,如果要实现这样的话,必须将\d+
改成\w+
(英数字下划线),如果不熟悉正则基础的去恶补知识吧
而通常情况下rules配置中我也最常用的就是\d+
和\w+
这两个正则匹配符
复杂点的多参数伪静态 ¶
多个参数时其实也很容易理解,看看:
'uiui<userId:\d+><userName:\w+>-balabala<age:\d{2}><type:\d><width:\d+>-<height:\d+>.html' => 'test/abc'
这里一共有6个参数,userId、userName、age、type、width和height,其中age只匹配2位数字,type只匹配一位数字
小弟又提供测试代码给你复制了多好:
echo Url::to(['test/abc',
'userId' => 65535,
'userName' => 'jay',
'age' => 18,
'type' => 4,
'width' => 200,
'height' => 100,
]);
结果就生成了“http://xxx.com/uiui65535jay-balabala184200-100.html”
对了你有没有发现,test控制器不用建立abc方法也能生成?其实生成URL只是检查rules配置,匹配了就生成,它不管你有没有控制器方法(学过其它框架的话也很清楚,这个不新鲜了)
这个URL代入get参数后就是
$_GET = [
'userId' => 45678,
'userName' => 'kkqbx',
'age' => 18,
'type' => 2,
'width' => 1024,
'height' => 768,
];
rules的规则定义顺序 ¶
相似的几个伪静态共存时,精确的伪静态必须放在最前面,模糊的放后面,比如有以下伪静态
'rules' => [
'a<id:\w+>.html' => 'test/a',
'abc.html' => 'test/b',
]
当访问/abc.html
时永远不会路由到test/b
,因为它已经被a<id:\w+>.html
这条规则匹配成功,不再往下匹配了
想匹配test/b的话就要将abc.html
这条规则移到test/a的规则前面才可以
重要知识点:原则上就是越精确的伪静态就越靠前就好
比如abc.html
是没有正则表达式的,所以它绝对精确地描述了匹配内容,如果将带正则的规则放在前面就会被别人匹配掉了(因为正则匹配其实就是一种模糊匹配)
题外话:分享我的命名风格 ¶
如果伪静态URL是提供AJAX请求返回数据用的,我在伪静态里一般都使用.json
结尾
显示一个页面则用.html
而比如是登陆、充值、删除这些,虽然操作后服务端也是返回json给前端,但它的“主要行为目的不是为了取数据,而是为了处理数据”,则我会命名为.do
甚至验证码的我就会用.jpg
了,附上示例代码:
'rules' => [
'users.html' => 'user/list',
'users/<page:\d+>.json' => 'user/list-data',
'users/<id:\d+>.html' => 'user/info',
'login.do' => 'user/login',
'users/delete.do' => 'user/delete',
'captcha.jpg' => 'site/captcha',
'cgi-bin/pay-order.aid8877.bid<bid:\w+>' => 'banner/compose',
]
最完善的URL生成和伪静态定义知识请见英文官方文档,讲得比中文官方文档还要完整
但我讲的这些目前至少是够你做一般的程序用