20.4 CGI:帮助Web服务器处理客户端数据
20.4.1 CGI介绍
Web开发的最初目的是在全球范围内对文档进行存储和归档(大多是教学和科研目的的)。这些零碎的信息通常产生于静态的文本或HTML.
HTML是一个文本格式而算不上是一种语言,它包括改变字体的类型、大小、风格。HTML的主要特性在于它对超文本的兼容性,文本以某种高亮的形式指向另外一个相关文档。可以通过鼠标点击或者其他用户的选择机制来访问这类文档。这些静态的HTML文档在Web服务器上,在有请求时,将被送到客户端。
随着因特网和Web服务器的形成,产生了处理用户输入的需求。在线零售商需要能够单独订货,网上银行和搜索引擎需要为用户分别建立账号。因此发明了这种执行模式,并成为了Web站点可以从用户那里获得特殊信息的唯一形式(在Java applet出现之前)。反过来,在客户提交了特定数据后,就要求立即生成HTML页面。
现在Web服务器仅有一点做得很不错:获取用户对文件的请求,并将这个文件(也就是说HTML文件)返回给客户端。它们现在还不具有处理字段类特殊数据的机制。将这些请求送到可以生成动态HTML页面的扩展应用程序中并返回给客户端,这些还没有成为Web服务器的职责。
这整个过程开始于Web服务器从客户端接到了请求(GET或者POST),并调用合适的程序。然后开始等待HTML页面——与此同时,客户端也在等待。一旦程序完成,会将生成的动态HTML页面返回到服务器端,然后服务器端再将这个最终结果返回给用户。服务器接到表单反馈,与外部应用程序交互,收到并返回新生成的HTML页面都发生在一个叫做Web服务器CGI(标准网关接口,CommonGateway Interface)的接口上。图20-3描述了CGI的工作原理,逐步展示了一个用户从提交表单到返回最终结果Web页面的整个执行过程和数据流。
图 20-3 CGI工作概要图。CGI代表了在一个Web服务器和能够处理用户表单、生成并返回动态HTML页的应用程序间的交互
客户端输入给Web服务器端的表单可能包括处理过程和一些存储在后台数据库中的表单。需要记住的是,在任何时候都可能有任何一个用户去填写这个字段,或者点击提交按钮或图片,这更像激活了某种CGI活动。
创建HTML的CGI应用程序通常是用高级编程语言来实现的,可以接受、处理数据,向服务器端返回HTML页面。目前使用的编程语言有Perl、PHP、C/C++或Python.
在我们研究CGI之前,我们必须告诉你典型的Web应用产品已经不再使用CGI了。
由于它词义的局限性和允许Web服务器处理大量模拟客户端数据能力的局限性,CGI几乎绝迹。Web服务的关键使命依赖于遵循像C/C++这样的语言规范。如今的Web服务器典型的部件有Aphache和集成的数据库部件(MySQL或者PostgreSQL) 、Java (Tomcat) 、PHP和各种Perl模块、Python模块,以及SSL/security。然而,如果你工作在私人小型的或者小组织的Web网站上的话就没有必要使用这种强大而复杂的Web服务器,CGI是一个适用于小型Web网站开发的工具。
更进一步来说,有很多Web应用程序开发框架和内容管理系统,这些都弥补了过去CGI的不足。然而,在这些浓缩和升华下,它们仍旧遵循CGI最初提供的模式,可以允许用户输入,根据输入执行拷贝,并提供了一个有效的HTML作为最终的客户端输出。因此,为了开发更加高效的Web服务,有必要理解CGI实现的基本原理。
在下一部分中,我们将会关注在cgi模块的协助下如何在Python中建立一个CGI应用程序。
20.4.2 CGI应用程序
CGI应用程序和典型的应用程序有些不同。主要的区别在于输入、输出及用户和计算机交互方面。当一个CGI脚本开始执行时,它需要检索“用户-支持”表单,但这些数据必须要从Web的客户端才可以获得,而不是从服务器或者硬盘上获得。
这些不同于标准输出的输出将会返回到连接的Web客户端,而不是返回到屏幕、CUI窗口或者硬盘上。这些返回来的数据必须是具有一系列有效头文件的HTML。否则,如果浏览器是Web的客户端,由于浏览器只能识别有效的HTTP数据(也就是MIME头和HTML),那么返回的也只能是个错误消息(具体的就是因特网服务器错误).
最后,可能和你想象的一样,用户不能与脚本进行交互。所有的交互都将发生在Web客户端(用户的行为)、Web服务器端和CGI应用程序间。
20.4.3 cgi模块
在cgi模块中有个主要类,即FieldStorage类,它完成了所有的工作。在Python CGI脚本开始时这个类将会被实例化,它会从Web客户端(具有Web服务器)读出有关的用户信息。一旦这个对象被实例化,它将会包含一个类似字典的对象,具有一系列的键-值对,键就是通过表单传入的表单条目的名字,而值则包含相应的数据。
这些值本身可以是以下三种对象之一。它们既可以是FieldStorage对象(实例),也可以是另一个类似的名为MiniFieldStorage类的实例,后者用在没有文件上传或mulitple-part格式数据的情况。MiniFieldStorage实例只包含名字和数据的键-值对。最后,它们还可以是这些对象的列表。这发生在表单中的某个域有多个输入值的情况下。
对于简单的Web表单,你将会经常发现所有的MiniFieldStorage实例。下边包含的所有的例子都仅针对这种情况。