"Web 2.0" 是指由用户主导网站内容的创作。自从这个概念兴起以来,网络编程就成为了一个热门话题。一直以来,用 Python 创建网站是相当繁琐的,所以也很少有人这么做。因此人们创建了许多框架和辅助工具来帮助开发者创建更快更可靠的网站。这篇 HOWTO 介绍了几种 Python 结合 web 服务器创建动态内容的方法。当然,因为这个话题涉及的内容太广,很难在单独的一篇文档里进行详细的描述。所以这里就只对一些当前流行的库作简要的概述。
参见:这篇 HOWTO 试图对 Python 的 Web 开发作一个概览,但不能总是按预期及时地更新。Python 的 Web 开发正在迅速发展,所以 wiki 上的可能与近期的发展更为接近。
当一个用户访问网站时,他们的浏览器会与网站的服务器进行连接(这称为)。服务器在文件系统中寻找文件,并将其发送回用户的浏览器(这称为)。这就是底层 HTTP 协议的大致工作原理。动态网站不是基于文件系统中的文件,而是以程序为基础。当请求到来,运行在服务器上的程序就会生成相应内容并发送回用户。它们可以处理用户的各种数据,例如列出公告板上的帖子,显示你的邮件,配置软件,或者只是显示当前时间。这些程序能用服务器支持的任意语言完成。自从大部分的服务器开始支持 Python,用 Python 创建动态网站就变得十分简单了。
大多数的 HTTP 服务器是用 C 或者 C++ 写的,它们不能直接执行 Python 代码,所以服务器和程序之间就需要有一座桥。网桥,或者更确切地称为接口,决定了程序如何与服务器进行交互。
为了创建尽可能好的接口,人们作出了无数尝试,但只有少数的几个值得关注。
不是每一个服务器都支持所有的接口。许多服务器只支持老的,现在已经过时的接口。然而,它们经常可以通过第三方模块扩展来支持新的接口。
这个接口,通常被称为 "CGI",是最古老的,几乎被所有 web 服务器很好地支持着。在处理单个请求时,程序由服务器启动,通过 CGI 与服务器进行通讯。因而每个请求来临时都要花一定时间去启动新的 Python 解释器。这就使得整个接口在低负载状态的时候才能正常使用。
CGI 的优点在于它很简单——用 CGI 写一个 Python 程序大概就是三行代码的事情。这种简易性造成了一种误解:它对开发者的帮助聊胜于无。
虽然还有可能用 CGI 写程序,但已经不建议这么做了。通过使用本文稍后提到的 WSGI,就能模仿 CGI 的方式写程序,而且在迫不得已的时候,它们也能作为 CGI 运行。
参见:Python 标准库包含了一些模块来帮助创建简单的 CGI 程序:
Python 的 wiki 有专门描述 CGI 脚本的页面,里面有关于 CGI 在 Python 中的一些额外信息。
你可以用这个简短的 CGI 程序来测试你的服务器是否支持 CGI。
- #!/usr/bin/env python
- # -*- coding: UTF-8 -*-
- # enable debugging
- import cgitb
- cgitb.enable()
- print("Content-Type: text/plain;charset=utf-8")
- print()
- print("Hello World!")
根据你服务器的配置,你可能需要使用用
或者
- .py
扩展名来保存此代码。出于对安全的考虑,此文件也可能需要放置在
- .cgi
目录中。
- cgi-bin
也许你想知道
那行代码有什么作用。这行代码显示良好的错误回溯,而不仅仅是崩溃时在用户的浏览器上显示 "服务器内部错误"。这有利于进行 debug,但存在一定的风险暴露某些机密的数据给用户。基于这个原因,你不应该在生产环境中使用
- cgitb
模块。还有,终端用户不会喜欢在浏览器上看到 "服务器内部错误" 这样不伦不类的信息,所以你应该捕获所有异常,并显示合适的错误页面。
- cgitb
如果你没有自己的服务器,这就不适用于你。你可以检查服务器是否如常工作,如果不是,你就可能需要联系你网站的管理员。如果它是一个庞大的主机,你可以尝试提交问题请求 Python 支持。
如果你就是自己的管理员,或者基于测试的目的想在自己的电脑上安装 CGI,你就必须自己进行配置。因为每个服务器的配置选项都不用,所以配置 CGI 没有通用的方法。现在使用最广的免费服务器是,或者简称 Apache。通过系统的包管理工具,Apache 可以轻易地安装到几乎所有的系统。 则是另一个选项,据说有着更好的性能。在许多系统中,可以使用包管理工具来安装这个服务器,所以不再需要手动来编译它。
就足够了。这篇教程也提到一些最常见的问题。
- +ExecCGI
进行设置。
- cgi.assign
在运行 CGI 脚本的时候,时常会出现一些小的烦人的问题。有时看起来似乎正确的脚本不会像预期那样工作,原因是某些小的隐藏问题很难被发现。
以下是一些潜在的问题:
位(修改执行权限)。使用
- +x
可能会解决问题。
- chmod a+x your_script.py
的状态下运行。所以可以试着去修改文件的所有权,或者用
- www-data
命令将文件改为可读状态。
- chmod a+r your_script.py
中寻找 Python,但如果该目录不存在或者路径不正确,查找都会失败。你如果知道你的 Python 安装在哪里,可以使用绝对路径。命令
- /usr/bin/python
和
- whereis python
都能帮助你找到它的安装位置。一旦你知道了正确的路径,你就可以相应地修改 shebang:
- type -p python
。
- #!/usr/bin/python
可能会有问题。
- mod_python
能够自己处理 CGI 脚本,但也能成为问题的源头。
- mod_python
从 PHP 来的人经常很难抓住用 Python 进行 Web 开发的要领。他们第一时间想到的通常是
,因为他们想
- mod_python
等价于
- mod_python
。事实上,它们之间有很多不同。
- mod_php
做的是将解释器嵌入到 Apache 的进程里,这样就不用再为每个请求各启动一个解释器,从而加快了运行速度。另一方面,PHP 经常混合着 html,但 Python 不是。实际上,在 Python 中与之相当的是模板引擎。比起
- mod_python
,
- mod_php
本身要强大得多,它提供了更多的权限来访问 Apache 的内部。在一个 Python 混合 HTML 的 "Python 服务器页面" 模式 (与 JSP 相似) 下,它可以模拟 CGI 工作。它还有一个 "发布者",可以指定一个文件来接收所有请求并决定接下来如何处理它们。
- mod_python
确实有很多问题。不同于 PHP 解释器,Python 解释器在运行文件时是使用缓存的,所以修改文件时需要重启服务器。另一个问题是关于 Apache 的工作原理 — Apache 启动子进程来处理请求,即使用不到 Python,每个子进程依然要加载整个 Python 解释器。这让整个服务器运行得更慢了。另一个问题则是,如果不重新编译
- mod_python
,它就不能切换版本 (例如从 2.4 升级到 2.5),理由是
- mod_python
依赖于一个特定版本的
- mod_python
。还有,
- libpython
是绑定到 Apache 上的,所以用
- mod_python
写的程序不能轻易移植到在其他 Web 服务器上。
- mod_python
已经有很多原因解释了应该避免用
写新的程序。在特定情况下,使用
- mod_python
进行开发还是不错的,但自从 WSGI 出现后,我们就可以在
- mod_python
下运行 WSGI 程序了。
- mod_python
FastCGI 和 SCGI 尝试以另一种方式解决 CGI 的性能问题。取代了在 Web 服务器中嵌入解释器的做法,它们使用了一个长时间运行的后台进程。这还是一个能让服务器与后台进程 "说话" 的模块。既然后台进程独立于服务器,它就可以用包括 Python 在内的任何语言来完成。使用的语言只需要一个能处理与 Web 服务器通信的库。
正如 SCGI 本质上就是一个 "简单的 FastCGI",FastCGI 和 SCGI 之间的差距非常小。因为仅有少数的服务器支持 SCGI,大多数人使用工作方式相似的 FastCGI。几乎所有能应用于 SCGI 的也能应用于 FastCGI,所以我们只讨论后者。
如今,FastCGI 不再被直接使用。就像
, 它只在 WSGI 的应用开发中使用。
- mod_python
每个 Web 服务器都需要一个特定的模块。
是先出来的一个,但因为一些许可问题,有时候会被误认为是收费的。
- mod_fastcgi
是一个体积更小,可兼容的替代选择。
- mod_fcgid
一旦你将模块安装配置完成,就可以用下面的 WSGI 应用进行测试:
- #!/usr/bin/env python
- # -*- coding: UTF-8 -*-
- import sys, os
- from html import escape
- from flup.server.fcgi import WSGIServer
- def app(environ, start_response):
- start_response('200 OK', [('Content-Type', 'text/html')])
- yield '<h1>FastCGI Environment</h1>'
- yield '<table>'
- for k, v in sorted(environ.items()):
- yield '<tr><th>{0}</th><td>{1}</td></tr>'.format(
- escape(k), escape(v))
- yield '</table>'
- WSGIServer(app).run()
这是一个简单的 WSGI 应用,但你需要先安装 [flup][] 模块来处理底层的 FastCGI 访问。
参见:有一些关于的文档, 其中多数的经验可以复用到其他 WSGI 兼容的框架和库。除了
的部分需要修改,这里的例子可以直接使用。在 Django 中使用也是差不多的。
- manage.py
是一次企图摆脱底层网关束缚的尝试。上文提到的 FastCGI,SCGI 和 mod_python 大多是用来部署 WSGI 应用的,mod_wsgi 则是直接将 WSGI 应用嵌入到 Apache 服务器中。mod_wsgi 是专门设计来托管 WSGI 应用。比起使用其他更底层,还需要胶水语言的模块,使用它开发 WSGI 应用程序更为简单。缺点是 mod_wsgi 仅限于 Apache 服务器;其他服务器则需要自己的 mod_wsgi 实现。
mod_wsgi 支持两种模式:嵌入模式,直接整合到 Apache 的进程中;守护进程模式,工作方式与 FastCGI 相似。
WSGI 已经提到过几次,这似乎意味着它很重要。事实上,它确实是。所以是时候来解释它了。
网络服务器网关接口 (Web Server Gateway Interface),或者简称 WSGI,在中有详细定义,是目前进行 Python 网络编程的最佳方式。虽然这对开发框架的程序员来说是一件好事,但一个普通的 Web 开发人员通常不需要跟它有直接的接触。当选择 Web 开发框架的时候,最好选择一个支持 WSGI 的。WSGI 最大的优点就是统一了应用程序的接口。如果你的程序兼容 WSGI,这就意味这你外层使用的框架支持 WSGI,你的程序可以部署到任意支持 WSGI 的 Web 服务器。你不再需要关心用户使用的是 mod_python,FastCGI,还是 mod_wsgi,因为使用了 WSGI 的程序可以在任何的网关接口上运行。Python 的标准库也包含了它自己的 WSGI 服务器——,一个可用作测试的小型服务器。
一个 WSGI 真正强大的特性是中间件。中间件是一个可以在软件上添加各种功能的层。现在可以使用的的中间件相当地多。例如,你不再需要为自己的程序单独编写会话管理 (HTTP 是一个无状态协议,当一个用户关联数个 HTTP 请求时,你的应用程序必须使用会话创建和管理状态)。压缩也可以用类似的方式完成,已有中间件利用 gzip 压缩你的 HTML 从而节省服务器宽带。通过中间件,验证的问题也可以轻松解决。
虽然 WSGI 可能看起来很复杂,但开始学习 WSGI 的收益是很大的,因为 WSGI 和它关联的中间件已经解决了许多开发网站会遇到的问题。
用来连接像 CGI 和 mod_python 这样的底层网关的代码就称为。其中一个代表是
,它支持 FastCGI 和 SCGI,还有。有一些服务器是用 Python 写的,比如
- flup
。但也存在用 C 完成的,可以作为替代使用。
- flup
现在可以使用的 WSGI 服务器有很多,所以一个用 Python 写的 Web 应用几乎可以部署在任何地方。这也是 Python 和其他 web 技术相比的一大优点。
参见:在可以找到 WSGI 相关代码的概述,其中还包含了一个涵盖很广的列表。你可能对已经包含在标准库中支持 WSGI 的模块感兴趣,即:
WSGI 到底给 web 应用开发者带来了什么?让我们通过一个应用来了解。这个存在已久的 Python 应用最初并没有使用 WSGI。
是使用最广的 wiki 软件包中的一个。它创建于 2000 年,比 WSGI 还早了 3 年。旧的版本运行在 CGI,mod_python,FastCGI 上时都需要不同的代码。
现在的版本添加了对 WSGI 的支持。通过 WSGI,不需要胶水语言,MoinMoin 可以部署到任意 WSGI 兼容的服务器。不同于前 WSGI 版本,现在 MoinMoin 作者可能在不知道的情况下就使用了 WSGI 服务器。
术语常在 "框架 foo 支持 MVC" 这样的描述中出现。比起具体特定的 API,MVC 更像是对代码整体的一种组织形式。许多 web 框架使用这个模型来帮助开发者,给他们的程序带来清晰的结构。稍大型的 web 应用就有相当多的代码,所以从一开始拥有一个有效的结构是非常重要的。通过这种方式,只要提前了解 MVC 结构,即使是其他框架的用户 (或者甚至是其他语言,因为 MVC 不是 Python 独有的) 也能轻松地理解代码。
MVC 代表三个组件:
虽然人们可能认为 MVC 是一个复杂的设计模式,但实际上它不是。它被用在 Python 中,是因为事实证明了它有助于创建简洁,可维护的网站。
笔记:虽然不是全部 Python 框架明确支持 MVC,但这不重要。创建网站的时候依然可以按照 MVC 模式,从用户交互逻辑 (控制器) 和模板 (视图) 中分离数据逻辑(模型)。因此也建议不要在模板中添加不必要的 Python 代码。否则就违背了 MVC 模式的工作理念,令程序变得难以理解和修改。
参见:英文 Wikipedia 有一篇关于的文章。文中详细地列出了各种语言的 web 框架。
网站有着复杂的结构。为了减轻 web 开发者的负担,让项目更容易编写和维护,许多工具被开发了出来。在其他语言的各种框架中都存在着类似的工具。一般情况下不会有人强迫开发者使用这些工具,而且通常 "最好" 的工具都是不存在的。某些工具会简化开发网站的流程,所以适当选择学习一部分还是不错的。
参见:实际网站的组件要比这里提到的要多得多。Python 的 wiki 中有一个叫的页面,里面有关于这些组件的详细叙述。
只有少数的库可以允许 Python 代码和 HTML 混合。虽然这样做很方便,但会导致代码非常地难以维护。基于这个原因,模板就诞生了。在最简单的情况下,模板只是带有占位符的 HTML 文件。在填充完占位符后,HTML 会被发送到用户的浏览器上。
Python 已经内置了一种方法来构建简单的模板:
- # a simple template
- template = "<html><body><h1>Hello {who}!</h1></body></html>"
- print(template.format(who="Reader"))
为了用庞杂的数据模型,判断和循环结构来生成复杂的 HTML 页面,像 Python 的和通常都是需要的。正好支持这种复杂的模板。
许多用于 Python 的模板引擎都是独立于框架的。其中一些定义成了某种容易上手的纯文本编程语言,部分原因是它被限制在特定的作用域内。还有模板使用 XML,这就保证了它的输出一定是有效的 XML。当然,其他种类的还有很多。
有些框架发布了自己的模板引擎或者推荐特定的一个。使用框架自己的或者推荐的通常都是不错的。
流行的模板引擎包括:
参见:因为用 Python 来完成一个模板引擎是相当容易的,所以许多模板引擎为了引起开发者的关注而开始了相互竞争。在 wiki 页面中列出了一个数量庞大且不断增长的模板引擎列表。上面列出的三个被认为是 "第二代" 引擎,是了解模板引擎的好例子。
,听起来很复杂,其实就是储存数据。数据可能来自博客条目的文本,布告栏的帖子,或者 wiki 页面的正文。当然,在 web 服务器中有多种不同的方式来存储信息。
因为在处理百万级数据时有着有着良好的性能,像或者这样的关系型数据库经常被使用。但还存在着像一样的小型数据库。SQLite 只使用一个单独的文件,附带于 Python 的模块。它没有其他依赖。对于较小的站点,SQLite 就足够了。
关系型数据库通过一种称为的语言进行查询。一般来说,Python 程序员不太喜欢 SQL,因为他们喜欢使用对象。通过使用一种叫 ORM(Object Relational Mapping) 的技术,Python 对象可以保存在数据库中。在后台,ORM 将全部面向对象的访问转化为 SQL 代码,所以开发者不用注意太多。大多数的框架在使用各种 ORM,而且使用的效果确实不错。
第二种可能就是将数据存储在普通的纯文本文件(有时候称为 "flat files")。对于简单的网站而言,这很容易实现,但如果网站经常更新数据,那就表现得不如尽人意了。
第三种可能则是使用面向对象的数据库(也称为 "对象数据库")。这种数据库存储对象数据的方式与程序运行时对象在内存中结构化的方式接近。(相比之下,ORM 将对象数据存储为表中的数据行以及行之间的关系。)直接储存对象的优点是几乎所有的对象都可以直接保存。反观关系型数据库,一些特别的对象就很难被表达。
框架通常都会对选择哪种存储数据方式的问题上给点建议。除非有特殊的应用场合,遵循它给的建议一般都能很好地满足存储需求。
参见:
在为网站运行编写代码的过程中,需要涉及到多种服务。不管网站的复杂性如何,它的目标是什么,提供特殊服务的代码其工作方式都是一样的。在 web 开发中,将常见问题的解决方法抽象出来转化为可复用的代码就叫做框架。也许你听说过最著名的 web 开发框架是 Ruby on Rails, 但 Python 也有自己的框架。其中有部分是受 Rails 启发或者是借鉴了 Rails 的想法。不过在 Rails 诞生之前,许多框架就已经存在了很长时间。
原来 Python Web 框架倾向于整合开发网站需要的所有服务,并集成一系列的开发工具。但没有哪两个 web 框架能够相互协作:没有经过深思熟虑的重构后,用 A 框架的开发的程序是不能部署在 B 框架上的。这种趋势推动了 "minimalist"(极简主意)web 框架的发展。这类型的框架只保留了让代码与 http 协议通信的工具,其他服务则需要在上层通过分开的组件逐一添加。为了让框架之间能彼此协作,一些标准应运而生。比如某个标准,可以允许不同的模板引擎相互替换使用。
随着 WSGI 的出现,Python Web 框架一直在向基于 WSGI 标准的互操作性上发展。现在不论是 "全栈" 的(提供开发最复杂网站需要的所有工具)还是微型的(minimalist),或者其他任意类型的 web 框架,都是由可运行在多个框架上的可复用组件集合而成。
多数的用户会可能选择一个拥有活跃社区的 "全栈" 框架。这些框架都渐渐地有了友好的文档,并且提供了一种最简流程来引导开发者在最短时间内完成功能齐全的网站。
现在框架的数量多到难以置信,所以这里不可能都一一提及。相对地,我们只简单地介绍几个最流行的框架。
是一个包含了数个紧密耦合组件的框架。其中的组件都是重新写的,相互配合得很好。Django 提供的 ORM 相当强大,而且简单易用。内置的在线用户管理界面能够让人们通过浏览器编辑数据库中的数据。为了照顾不会 Python 的网页设计人员,它的模板引擎是基于文本的。它还支持模板继承和过滤器(类似于 Unix 的管道)。Django 附带了许多便利的特性,例如通过生成 RSS feeds 和 generic views,几乎不用写 Python 代码就可以创建一个网站。
Django 还拥有一个庞大的国际社区,里面的成员创建了无数的站点。为了拓展 Django 的常用功能,还存在着大量的插件。这部分归功于 Django 友好的和。
笔记:虽然 Django 是 MVC 设计的框架,但它命名的方式有些不一样,你可以在中找到相关叙述。
Python 另一个流行的 web 框架是。TurboGears 使用现有的组件并用胶水语言组合它们,通过这种方法来实现无缝连接。在选择组件的时候,TurboGears 给予了用户充分的自由。例如 ORM 和模板引擎都可以改为使用非默认的软件。
可以在种找到相关文档,里面还有视频教程。TurboGears 也有一个活跃的社区,能回答最相关的问题。已经出版,这同样是一个学习 TurboGears 很好的起点。
TurboGears 最新的版本是 2.0,在 WSGI 支持和基于模组的架构的方向上更进一步。TurboGears2 的 WSGI 技术栈是基于另一个流行的组件兼容的 web 框架——。
框架 Zope 是一个 "古老原始" 的框架。它的化身 Zope2 是一个高度集成的全栈框架。它一个最有趣的特性是它与一个强大的面向对象数据库(Zope Object Database)紧密结合。由于其高度的集成性,Zope 最终的生态圈稍微有些孤立:为 Zope 编写的代码很难能在用在 Zope 以外的地方,反之亦然。Zope 3 开始致力于解决这个问题。Zope 3 将 Zope 重写成一套清晰独立的组件。这项工作开始于 WSGI 标准建立之前,但项目为 Zope 3 添加了对 WSGI 的支持。Zope 的组件已经在背后默默地工作了很多年,Zope 3 则将这些组件开放给更广泛的 Python 社区。甚至促成一个新的基于 Zope 组件的框架:
当前最强大和最受欢迎的内容管理系统——,就是基于 Zope 实现的。
实际可用的框架当然不止这些,还有许多其他的框架值得一试。
另一个被提到的框架是。Pylons 很像 TuroGears,但更强调灵活性,为此也牺牲了易用性。在 Pylons 中,几乎每一个组件都可以被替换。这就导致了每个单独的组件都需要很多文档。Pylons 是建立在的基础上,而 Paste 是一个方便 WSGI 使用的工具集。
这还不是所有。你可以在 Python wiki 中找到更多最新的信息。
参见:Python wiki 包含了一个范围很广的列表。大部分框架都有自己的邮件列表和 IRC 频道,在对应项目的网站就能找到这些信息。
来源: http://www.cnblogs.com/rainfd/p/howto_webservers.html