网址分发,如同写文章有 顺叙,倒叙,插叙 ,也有不少套路。
大致可分为三种基本模式 PHP的文件映射,Django的正则匹配,Quixote的模块函数查找。
相比PHP和Django而言,Quixote显得有些名不见经传,不过世界上最大的基于Python框架的网站 -- 豆瓣 ( douban.com ) ,正是基于它开发的。
1. 文件映射,也就是网址对应到文件。比如
http://www.zen-cart.com/forum/index.php
对应到
C:\project\bbs\forum\index.php
这样的好处是很直观,但纯粹的基于文件对应也有不爽的地方:
a.
如果想要实现一些漂亮的网址形式,比如 http://delicious.com/tag/china ,其中 china 是可以变化的参数 ,就常常要借助于HTTP服务器的 网址重写 URL Rewrite 功能。
相对其他方式而言,这种做法比较生硬。
b.
有一天,老板心血来潮,说所有的用户内容都需要付费成为高级会员才能浏览
形如 /user/用户名/ 的
/user/zsp/review
/user/zsp/note
/user/zsp/book
...
等等,都需要检查浏览者是否是高级会员。
Java中Struts框架中的 拦截器 Interceptor,Django中的 中间件 Middleware,Quixote中的 _q_access ,都可以方便地在 访问同种形式网址 时 统一做权限检查 的需求。
而单纯基于文件的网址映射模式,对此则比较被动。
当然,PHP中有一些类似 单点入口 之类的技巧,不少PHP框架也集成了其他的网址分发方式,可以规避这些麻烦 -- 这已经超脱了单纯的文件映射,成为一种复合的分发方式了。
工具本身的不足,几乎都可以通过其他方式来迂回。
决定生死的不是剑,而是用剑的人。
2. 正则匹配
看代码。眼中有码,心中无码。
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^articles/2003/$', 'news.views.special_case_2003'),
(r'^articles/(\d{4})/$', 'news.views.year_archive'),
(r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)
如上,通过正则,能很自然地从URL中提取参数。当然也有缺点
a.
当你有很多URL时,需要依次匹配正则来查找对应的URL,效率堪忧。
b.
每个函数都要写对应的正则,麻烦。
好吧,我承认,我很懒。
马云说:如果你想少干,就要想出懒的方法。要懒出风格,懒出境界。
PS:太阳下面无新鲜事,这句话我小时候就看过。
3. 模块函数查找
从某种意义上说,模板函数查找是文件映射方式的一种扩展和外延。
秀一段Quixote工程模块的组织结构,比如 /photo/people/用户名/news/lastest 将会对应到下面 news.py 中的 lastest 函数。
photo
|-- __init__.py
|-- people
| |-- __init__.py
| |-- news.py
与直接文件映射区别就是,它是一层一层找过去的。
定义名为 _q_access 的函数,可以某层URL做统一的处理。
定义名为 _q_lookup 的函数,可以处理那些可变的参数,
当然它也有缺点,比如连续出现多个可变参数,应付起来相对麻烦 -- 幸好,这种情况不是很多。
任何能把 字符串 映射成为 函数加参数 的方法都可以用做网址分发。
如果有时间,完全可以发扬DIY精神,Do It Yourself 。事实上我就是这么干的[注1],但代码比较晦涩,不细说了。
注释:
1. 我的URL Route代码
https://code.google.com/p/mayoufour/source/browse/trunk/mypylib/mypy/urlroute.py