status |
草稿 |
完成度20% |
1. Quixote ~ 豆瓣动力核心
1.1. 缘起
Quixote是由美国全国研究创新联合会(CNRI,Corporation for National Research Initiatives)的工程师A.M.Kuchling、Neil Schemenauer和Greg Ward开发的一个轻量级Web框架。和几乎所有的开源项目一样,Quixote也是为了满足实际需要而出世的。
CNRI当时在进行一个名为MEMS Exchange的项目( http://www.mems-exchange.org/ )。MEMS是微机电系统的缩写,制造一个MEMS设备往往需要多种制造设备,单个工厂可能无法提供所需的所有设备。因此,MEMS Exchange项目就是要整合起多家制造厂的资源,利用互联网派单和追踪制造过程,形成一个分布式的MEMS设备制造网络。
起初,他们做了一个Java版的客户端程序提供给用户,但他们发现,没有人愿意使用这个客户端程序,大家还是习惯性的用邮件发送加工过程。最终他们认识到,虽然客户端的表现力更强,功能也更完整,但相比起要下载一个庞大的程序起来,用户更加愿意使用他们每天面对的浏览器来做事情。于是,他们决定改到web界面上来,要做一个web应用。但是用Java的servlets开发web应用是一件非常低效的事情,所以他们选择了Zope(和现在不同,在1999年,Python的web应用框架没有什么选择的余地,基本上是Zope一家独大)。3个月的开发之后,他们得到了一个运转良好的系统。
然而,Zope带来的快乐并没有持续多长时间。几个月后,他们想提供更加复杂一点的界面,却发现用Zope写的代码难以维护和调试,在浏览器的文本编辑框里写代码也实在不是什么好的体验。由于当时除了Zope之外也没有什么别的Python web框架,他们决定:自己写一个!在2000年,编写一个新的web框架是类似于向风车挑战一样的事情,开发团队自嘲的用堂吉诃德的名字命名这个框架:Quixote。
以下使用Quixote 1.2版本为例进行介绍
1.2. 特性介绍
Quixote有以下几个特点:
1. 简单的URL分发规则
所有的web框架要解决的第一件事情就是:当用户输入一个URL,应该调用哪段代码来响应用户需求呢?这就是URL分发。与Django之类的基于正则表达式匹配来实现URL分发的框架不同,Quixote是基于URL的目录结构进行逐层查找实现的。
一个Quixote应用对应着一个Python的名字空间(通常是一个包)。URL的每一级目录映射到一个子名字空间上(模块或者子包),URL的最末一级映射到上一级名字空间中的一个函数上。该函数返回一个字符串,就是返回给浏览器的页面。例如,如果你的应用是放在app这个包下的,那么 http://www.example.com/hello/john 就对应app.hello.john(request)。末级目录则对应于_q_index函数,如http://www.example.com/hello/ 对应于app.hello._q_index(request)。就这么简单。
这种层级查找的结构还可以带来额外的好处:在目录层进行控制。在每一个目录层级进行查找之前,Quixote都会先运行当前名字空间下的_q_access(request)函数。比如你需要 http://www.example.com/settings/ 下的所有路径都只能由登录用户访问,那么只需要在 app.settings 这个名字空间(app/settings.py,或者app/settings/__init__.py)中定义一个_q_access(request)函数,在其中检查当前用户的登录状态(cookie可以从request对象获得),如果发现是未登录状态,抛出一个AccessError异常即可。
当Quixote执行代码时碰到异常,它会首先检查当前名字空间下有没有_q_exception_handler函数,如果有的话,则由这个函数处理异常,返回的字符串则为出错页面。如果没有定义这个函数,或者在执行它的时候又抛出了异常,则向上一级的名字空间查找_q_exception_handler函数,直至找到为止。所以,我们一般只需要在app/__init__.py中定义_q_exception_handler函数,就可以方便的实现定制出错页面了(当然你连这个也不定义也可以,Quixote提供了默认的出错页面)。
2. 易于实现RESTful的URL
刚才我们说 http://www.example.com/hello/john 对应 app.hello.john(request),那除了john之外,还有成千上万的用户的名字怎么办?不能每个为每个用户都定义一个函数吧?传统的方法是把会变的部分用URL参数的形式传进来,比如 http://www.example.com/hello/?name=bob 。但这种风格的URL既不好看,又不利于搜索引擎收录,要是能都像john一样直接成为URL的一部分多好啊!幸运的是,Quixote帮助你实现了这一点。
我们只需要在 app.hello 这个名字空间中定义一个 _q_lookup(request, component) 函数,当Quixote查不到 bob 这个名字时就会调用这个函数,把需要查找的名字 bob 传给 component 参数,用这个函数返回的结果作为找到的子名字空间或函数。在我们的例子里,代码就是:
这里我们返回了一个函数(也可以用定义了 __call__ 方法的类示例代替),这个函数将被调用以生成HTML页面。
3. 显式标记,拒绝魔术
Zen of Python中有一句“Explicit is better than implicit”,Quixote也是这个理念的贯彻者。所有可以通过URL访问到的函数和方法,必须在当级名字空间的 _q_exports 变量中列举出来(除了用 _q_lookup 实现的动态URL)。也就是说,要让 http://www.example.com/hello/bob 可以访问,必须在 app/__init__.py 中定义
1 _q_exports = ['hello']
4. 非常类似Python的模板语言
呃,或者说,就是Python语言。为了让程序员不用再学习一门模板语言,而是直接使用已经掌握的Python语法写模板,Quixote的模板语言PTL(Python Template Language,以.ptl作为文件名后缀)的语法和Python一模一样(除了后面要说到的[html]标记),在执行了quixote.enable_ptl()之后,这些.ptl文件就可以像普通的.py文件一样作为Python模块import进来。
但是既然是模板语言,就会有一些专门为了生成字符串的语法糖。在函数定义时,加上一个 [html] 标签就可以改变这个函数的表现,使得每执行一条语句,运行的结果如果不是None的话,就会以字符串的形式添加到函数的返回值里,而无需再使用return语句了。假设hello.ptl的内容如下:
我们来看看say_hello的返回值是什么:
因为say_hello函数由两条语句组成,这两行语句的运行结果分别返回一个字符串,因此运行结果就是 Hello, <em>Quixote</em>! 。这个设定可以大大方便模板的编写。
5. 内置的安全性支持
互联网上有很多寻找网站漏洞的攻击者,跨站脚本(XSS)是一个常见的攻击手段。这种攻击通常会在页面显示数据的地方插入一段恶意javascript代码,当有人浏览这个页面的时候,就会运行这段代码。比如在say_hello这个例子中,恶意用户输入的名字(也就是name参数)是"<script>alert('haha')</script>"的话,在模板没有安全性处理的情况下,页面就会输出Hello, <em><script>alert('haha')</script></em>,浏览这个页面的用户就会中招。幸好,PTL帮助我们解决了这个问题,它会自动将输入的数据进行HTML escape,就是用<、>等HTML实体替换掉危险的<、>等字符,这样输出的结果就是Hello, <em><script>alert('haha')</script></em>,安全了。
1.3. 快速起步
1.4. 案例讲解
1.5. 小结
::-- QiangningHong [DateTime(2008-09-28T13:11:31Z)] PageComment2