1 / 81

第 8 章 编写 CGI 程序

第 8 章 编写 CGI 程序. 本章分为基础和提高两部分内容。基础部分是指编写 CGI 程序的基础知识,内容包括公共网关接口、 CGI 程序及其测试,还包括 CGI 的程序功能分析及输入流分析等。提高部分包括编写与测试 CGI 应用程序,内容有信息传递方法、高级 CGI 应用程序、 CGI 程序的候选方案、加速 CGI 应用程序、 CGI 程序的客户端、使用 Javascipt 对象、安全性问题,以及 CGI 程序测试方法实例等。. 第 8 章 编写 CGI 程序. 8.1 概述 8.2 编写 CGI 程序基础 8.3 编写实用的 CGI 应用程序

katina
Télécharger la présentation

第 8 章 编写 CGI 程序

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第8章 编写CGI程序 本章分为基础和提高两部分内容。基础部分是指编写CGI程序的基础知识,内容包括公共网关接口、CGI程序及其测试,还包括CGI的程序功能分析及输入流分析等。提高部分包括编写与测试CGI应用程序,内容有信息传递方法、高级CGI应用程序、CGI程序的候选方案、加速CGI应用程序、CGI程序的客户端、使用Javascipt对象、安全性问题,以及CGI程序测试方法实例等。

  2. 第8章 编写CGI程序 8.1 概述 8.2 编写CGI程序基础 8.3 编写实用的CGI应用程序 8.4 CGI应用程序测试实例 本章小结与习题

  3. 8.1 概述 • 我们已经对Visual Prolog 6中的基本编程比较熟悉。此处不再对诸如类、接口、对象等概念进行叙述。也不会介绍Prolog中的回溯、子句、谓词等概念。此处假设读者对这些概念是熟悉的。本章中的例子不牵涉任何类及对象的创建,所以对于那些不熟悉面向对象语言的读者来说,应当比较易懂。 • 最后一个例子用Javascript处理客户端进程。它利用了Javascript的面向对象的特点。要阅读本章的内容,读者最好要熟悉Javascript的概念。要想详细了解Javascript的面向对象的特点,不妨到下面这个网站去浏览一下: http://www.webreference.com/js • 本章中讲述的三个CGI应用程序的例子都在文件cgitutorial.zip中。如果电脑中没有安装网络服务器,可以用压缩文件中自带的TinyWeb web server。

  4. 8.2 编写CGI程序基础 8.2.1 公共网关接口 8.2.2 CGI程序 8.2.3 测试CGI程序 8.2.4 用Visual Prolog 6创建CGI程序 8.2.5 测试Example1 8.2.6 应用程序功能分析 8.2.7 输入流分析

  5. 8.2.1 公共网关接口 • CGI是指公共网关接口,是由世界万维网组织协会推荐的一种网络服务器输入和输出信息流规范。 • 正如我们所知道的,HTML浏览器(如Internet Explorer, Netscape)是通过网络服务器发送和接受信息的。但是万维网的作用并不只是读取一些超链接HTML文件,还需要有交互。即数据要从浏览器流入和流出,其中包括用户输入到浏览器窗口的信息。网络服务器自己并不能解决所有问题,那么它是如何处理这些交互信息的呢?

  6. 8.2.1 公共网关接口 • 网络服务器只是一个最基础的部分,它可以输出HTML文件到浏览器,包括其它的可识别的MIME类型的文件。但它并不支持一些高级操作,比如进入数据库后台并返回数据库的请求给浏览器。为了加强网络服务器的功能,于是CGI就产生了。服务器和同一台主机上的CGI程序进行对话后,CGI应用程序就可以替服务器完成它无法完成的任务。比如进入数据库后台或执行复杂的搜索任务。应用CGI的网络服务器通常要比那些不用CGI的服务器可以发送更多的信息。

  7. 8.2.1.1 公共网关 • “公共”这个词代表能被所有的网络服务器接受的协议。“网关”这个词表示获得信息的行为,就像通过一个门或关口进入另一端的程序进程一样。抽象地说,网络服务器是网关的一端,而CGI应用程序表示网关的另一端,它们通过CGI彼此进行对话。

  8. 8.2.1.2 流 • 我们所说的术语流,是指信息处理时,每次只能处理数据队列中的一个字节。就好像一根管道,它的直径只能允许通过一个字节,这些字节以流的形式从通道的另一端流出,每次只有一个字节。 • 正如水不能同时在水管中朝两个方向流动一样,程序中的字节流也不能同时进行读和写操作。数据或者从流中输出(通常被称作可读流),或者输入到流中(可写流),但在单个程序中不能对同一个流同时进行读写操作。 • 对CGI程序来说,字符是ANSI格式的,是八位的字符。这一点以后必须要注意,因为Visual Prolog默认的是UNICODE字符,它是十六位字符。Visual Prolog中有专门用来接收ANSI字符流的谓词,所以处理流并不是问题。最后需要指出的是,当我们浏览因特网的时候,数据流通过因特网通道流出到浏览器,一次只有一个字节。我们甚至注意不到他的通过,因为一旦单个字符到达浏览器,他们很快被组合起来,所以我们看到的好象是那些字节同时到达。

  9. 8.2.1.3 MIME类型 • MIME(Multipurpose Internet Mail Extensions)比较确切的中文名称为“多用途互联网邮件扩展”。它是当前广泛应用的一种电子邮件技术规范,基本内容定义于RFC 2045-2049。 • MIME的目标之一是在数据文件和用于显示和编辑该文件类型的应用程序之间建立联系。MIME通过为每种数据文件提供一个内容类型来实现这一点。 • MIME类型是Internet的命名数据类型的一个标准. 数据类型名由两部分组成,第一部分是说明数据的基本类型,如图像、视频、音频、文本等。由于文本有不同的类型,如C源程序、英文文本,以及保存图像有多种格式,所以数据类型的第二部分是用来说明它的特殊类型。image/gif就是一个恰当的例子。第一部分images说明它是一个图像文件,第二部分gif说明它是以GIF格式保存的。

  10. 8.2.1.3 MIME类型 • 在信息以流的形式被发送到浏览器的同时,服务器会在流的开头加入报头,包括数据的MIME类型。图8.1就是一个典型的例子,它说明了从服务器发送到浏览器的信息的格式。 图8.1 服务器到浏览器的信息格式

  11. 8.2.1.4 报头 • 在这里,报头是指加在真正数据前的嵌入流中的一行文本,该文本后跟回车符。在上面的例子中,数据上面那一行就是服务器发送到浏览器的报头。之间用一行空白行把报头和正文分开。 • 例子中报头的内容类型“content-type”这一行用来说明数据的MIME类型,这一行是专门应用于CGI程序的,因为当Web服务器调用一个CGI应用程序的服务来提供要传送给浏览器的信息时,它是忽略CGI程序提供的数据MIME类型的。所以,依照协议CGI程序必须在实际数据前加上报头(用一个空白行分开)。这一点在编写CGI应用程序的时候必须注意,因为不管是忘记了报头还是空白行(在实际数据和报头之间),都会带来很多麻烦。

  12. 8.2.2 CGI程序 • CGI应用程序或网关程序(见图8.2)是一个可执行程序(通常是exe文件),它并不通过键盘或鼠标接收任何信息。它并不是一个可交互程序(一个CGI程序应该是一个可交互的应用程序)。这种程序通常被称作控制程序,它通过标准stdin流接收输入信息,通过标准stdout流输出。报头的其他部分是在CGI应用程序完成其工作后由Web服务器加上的,然后这些编译好的信息被传送到浏览器。 图8.2 CGI应用程序或网关程序

  13. 8.2.2 CGI程序 • 对CGI程序来说,一旦启动,CGI应用程序在执行后会自动结束,而不需要任何输入来作用。这就像DOS中的xcopy、format命令一样,也是自动执行的。 • CGI程序不仅仅是一个控制台应用程序,它还等待接收符合规范的输入信息,并且输出信息也必须符合CGI规范。 • 在特定环境下,CGI程序也可以写成DLL文件,但这种变更是依赖于Web服务器的。甚至也可以是其它可能的外部变化。比如说,bat文件也能做成CGI程序,前提是假设Web服务器被设置为支持该文件作为CGI应用程序。我们不要陷入这些变更。在本章中我们把CGI程序都认为是符合CGI规格的可执行控制台应用程序。

  14. 8.2.2.1 stdin与stdout • 在很多程序语言中都有对stdin的定义,它是一个专门用来接收来自操作系统底层输入的流。程序(比如用VisualProlog写的程序)可以读取stdin流并且将该流给出的字符作为程序的输入。同样,stdout也是一个由操作系统控制的流,用来接收程序的输出信息。 • 不同程序的stdin和stdout流可以连接在一起。例如,A程序写入信息到stdout,然后调用程序B,程序B用stdin流接收由程序A输出的信息。这就是网络服务器最基础的转换机制。在前面的例子中,A就代表网络服务器,B代表CGI应用程序。而stdin流和stdout流通常被放在一起称为控制台。

  15. 8.2.2.2 CGI中的信息流 • 信息流是在客户向服务器发送请求时产生的。就像前边提到的,客户端会把它的处理能力和所请求的信息通知Web服务器。图8.3说明了浏览器(客户)向服务器发送的信息内容。 图8.3 浏览器(客户)向服务器发送的信息

  16. 8.2.2.3 环境变量 • 所有的操作系统都允许程序向计算机的RAM中插入形如name=value 的关系式,即所谓的环境变量。它是计算机RAM(随机存储器)中的某个地方。如DOS中的路径设置就是一个环境变量。我们可以通过SET命令来查看DOS(或 Windows)系统中的环境变量。仅需在命令行提示符下输入SET命令,控制台就会显示所有可用的环境变量(在显示列表中也可以看到路径)。 • 环境变量的概念中最好的一个优点就是我们可以设置自己的变量并且为它们赋值。 • 虽然值是字符串型的,但并不必给出引用。所有值都是以字符串的形式存储的,并且以字符串的形式被Visual Prolog程序取回。CGI应用程序中环境变量的重要性在于服务器用各种环境变量来给CGI程序传送信息。

  17. 8.2.2.3 环境变量 • 我们已经知道服务器在调用CGI应用程序之前把许多的数据放在stdout流里,但是CGI应用程序是如何知道要读入的数据有多少呢?为了能做到这一点,服务器把数据的长度赋给一个叫CONTENT-LENGTH的环境变量,CGI程序通过这个变量的值得知要从流中读入的字符数量。 • 除了内容长度,许多web服务器在启动一个CGI应用程序之前还会先设置如下的标准环境变量。有些服务器还可能对环境变量进行一些可能的变动,这主要取决于web服务器。CGI程序反过来也可以寻找到这些环境变量并使用相应的变量值。

  18. 8.2.3 测试CGI程序 • 为了测试CGI应用程序,我们需要有一个安装好的服务器,还要有CGI程序。还必须支持HTML文件,它通过网络服务器激活一个CGI程序。当然,这是随着程序的不同而不同的。学完这些例子后就会加深对所支持文件的了解。 • 前边已经讲过,CGI程序必须和服务器在同一台电脑上。考虑到安全问题,服务器只能通过一个特定的路径(该路径称为web路径)从主机上读取文件。所以,CGI程序(CGI可执行文件和HTML文件)可以放在这样的路径上,否则,一些恶意用户可能会试着非法读取。

  19. 8.2.3 测试CGI程序 • 同样,网络服务器只能激活在正确路径上安装的CGI程序。CGI程序不是放在网络上的任何地方都可以的(有些服务器可以,但不是全部)。现在,所有服务器都有参数配置方法(一个独立的配置文件或.ini文件或者windows注册表)来设置各种参数。其中一个很重要的参数就是CGI程序的存放路径。当我们为CGI程序瞄准了Web服务器时,要知道的第一件事就是该Web服务器如何配置它的CGI应用程序路径。 - 服务器的选择 -CGI程序的存放位置

  20. 8.2.3.1 服务器的选择 • 如上所述,Web服务器不只是一些复杂的软件,有许多免费的Web服务器可以选择。在http://www.serverwatch.com/stypes/index.php/d2Vi上就列出了很多。其中包括免费的软件和商业的软件。Web服务器的复杂性主要在于对web路径的设置和对Web服务器的CGI程序路径的设置。 • 安装服务器时同时也要在计算机上安装TCP/IP协议(如果已经能浏览因特网,说明已经装好)。一旦成功安装服务器之后,就可以通过服务器的IP地址或机器的域名来获得服务器上的数据。现在的CGI程序能够与大部分的服务器一起很好地运行,包括微软的windows 2000的IIS5 web server。

  21. 8.2.3.2 CGI程序的存放位置 • 确保CGI程序存放在服务器的正确路径上。随着服务器的不同,这些存放路径也是不同的。在本章,我们都认为是存放在下面这个路径上http://localhost/cgi-bin/ <APPNAME>,服务器上的浏览器可通过这个URL调用CGI程序。 • 比如一个名叫example1.exe的CGI程序,那么它在服务器上的URL应该是:http://localhost/cgi-bin/example1.exe,这样它才是可达的。

  22. 8.2.4 用Visual Prolog 6创建CGI程序 • 我们可以把cgitutorial.zip中的example.zip解压,然后对这个Visual Prolog例子进行测试。也可以根据下面的指导步骤自己重新创建一个。 1) 新建一个Visual Prolog 项目,注意Ui Strategy 中是Console,见图8.4所示。 图8.4 新建一个Visual Prolog 项目

  23. 8.2.4 用Visual Prolog 6创建CGI程序 2) 观察主项目树 这时就会显示出主项目树,其中包括由VDE决定的项目所需要的文件,见图8.5所示。 图8.5 主项目树

  24. 8.2.4 用Visual Prolog 6创建CGI程序 3) 建立项目 现在,打开build菜单,选中Build菜单项或者按组合键Alt-F9。随着建立过程的继续,VDE会调用相关的PFC(Prolog Foundation Classes)文档,这些文档在项目树中是看不到的。建立完毕后的项目树如图8.6所示。 图8.6 主项目树内容

  25. 8.2.4 用Visual Prolog 6创建CGI程序 4)修改代码 双击项目树中的文件example1.pro,并转向下面的代码: clauses run():- console::init(), succeed(). % place your own code here end implement example1 goal mainExe::run(example1::run). 可以清楚地看到,程序的主要目标调用了被称作run的一个谓词,该谓词来自PFC模块 mainEXE。然后PFC再激活example1.pro中的run()谓词。看下面所示的程序: run():- console::init(), succeed(). % place your own code here

  26. 8.2.4 用Visual Prolog 6创建CGI程序 将上面的代码修改为如下的代码形式: run():- console::init(), % Line 1 OutStream = console::getConsoleOutputStream(), %Line 2 OutStream:setMode(stream::ansi(core::ansi)), %Line 3 stdIO::write("Content-type: text/html\n"), %Line 4 stdIO::write("\n"), %Line 5 stdIO::write( "<html><body><h1>Hello World!</h1></body></html>"). % Line 6 (Don't forget the last dot!)

  27. 8.2.4 用Visual Prolog 6创建CGI程序 5)分析代码 现在让我们逐行分析这些代码: 第一行:这一行是Visual Prolog必须要有的,所有的程序都要用到console,都必须以console::init()开始。 第二行:获得stdout流对象,并将其赋给叫做Outstream的变量。前面讲过,CGI程序希望发送它的输出到stdout。这一行执行后,程序的输出将自动指向stdout(所有的write语句都会写入到stdout)。 第三行:在Visual Prolog中,默认的读写字符是16位UNICODE码,但我们这里需要的是8位的ANSI,这一行就是用来把16位的UNICODE码转化成8位的ANSI码。

  28. 8.2.4 用Visual Prolog 6创建CGI程序 第四行:现在,CGI程序将第一行传送给发出请求的服务器。正如前面所讲到的,这些数据必须要有一个头部。头部用来设置数据的MIME类型,这里声明的数据类型是text/html的MIME 类型,注意这一行以换行符(\n)结束。 第五行:报头中必须要用一空白行把头部和正文分开,这是CGI规范强制要求的。所以CGI程序发送一个空白行(\n)。在CGI程序中经常会忘掉这个要求,这时可能会带来程序的错误执行。 第六行:最后,真实数据被写入到stdout。在这个例子中,程序仅是简单创建并发送了一个HTML文件,这个文件只包括两个字:“Hello World!”。

  29. 8.2.5 测试Example1 • 依照前边所讲的把它放在服务器的正确路径上,然后用合适的浏览器进入下面这个URLhttp://localhost/cgi-bin/example1.exe。

  30. 8.2.6 应用程序功能分析 • 现在CGI程序Hello World (Example1)已经不是原先的样子了。它很简单,但它可以充当很多复杂工作的基础。就拿最后一行为例,这一行完成对HTML页的创建并且发送stdout流传送给服务器,服务器再把该页发送到发出请求的浏览器上。如果我们建立了一个数据库并在数据库后台加入一些处理数据库的谓词,就可以很轻松地建成一个管理系统。

  31. 8.2.7 输入流分析 • 就像前面所指出的,在这里我们忽略了服务器提供给程序的输入,如果CGI程序需要接收输入的话,就必须对stdin流进行读操作,然后对信息进行处理。而且必须检查好在CGI应用程序执行时设置的环境变量。这可能有些复杂,但幸运的是,在Visual Prolog中创建CGI程序时我们根本不必做很多编程。例如,如果想知道CGI程序接收了什么数据,我们只需用谓词cgi::getString()就可以了(项目中必须把PFC中的程序包cgi.pack包括在内)。如果想以更方便的形式得到数据的话,我们可以用cgi::getParamList()谓词。一个个的数据被谓词cgi::getParamList()组合为与环境变量相似的名值对。

  32. 8.3 编写实用的CGI应用程序 8.3.1 将信息从HTML文件传输至CGI程序 8.3.2 解释信息流的高级CGI应用程序 8.3.3 信息从网络服务器到浏览器的传输 8.3.4 CGI应用程序简评 8.3.5 取代CGI程序的候选方案 8.3.6 加速CGI应用程序 8.3.7 CGI程序的客户端 8.3.8 使用Javascript对象的高级CGI应用程序 8.3.9 安全性问题 8.3.10 防止CGI程序被盗链 8.3.11 小结

  33. 8.3.1 将信息从HTML文件传输至CGI程序 • 在上面的图8.3中, 我们展示了由浏览器向服务器发送信息流的详细资料。大部分全球信息网的实践由发送这类请求的浏览器组成。网络服务器依次处理这些请求同时把需要的MIME类型数据送给浏览器。问题到那里还未完结。在HTML中,我们能利用HTML FORM的元素嵌入特殊的交互窗体,在FORM元素内,我们可以使用像INPUT,TEXTAREA 等的交互式窗体。进入这种窗体的数据可以被分发到网络服务器。以这种形式在窗体中指定下列内容(参见图8.7): 网络服务器对窗体信息应采取何种措施; 应使用哪种方法来实现该处理。

  34. 8.3.1 将信息从HTML文件传输至CGI程序 • 如此例所示,ACTION 语句的后面只是一个 URL,它指定被网络服务器调用的CGI应用程序。在上图给出的例子中,它是一个被称为prgm.pl的PERL应用程序。数据是被网络服务器使用GET方法传给prgm.pl的。 图8.7 窗体信息

  35. 8.3.1.1 GET方法 • 在一个GET程序中,传递给CGI程序的全部数据在从浏览器被送到网络服务器的时候是被组合进URL内。假如我们要传送三个变量(名字,姓和电子邮件地址)及他们的数值到被称为myemailer.exe的CGI应用程序,这时URL可以写作: http://localhost/cgi-bin/myemailer.exe?firstname=sabu&lastname=francis&email=sabu@somewhere.com

  36. 8.3.1.1 GET方法 • 当汇编这些URL的时候,非法的字符要首先被转换到他们的URL编码形式。 举例来说, 如果任意一个数值包含有一个空格,它必须被记为%20,而一个冒号(:)将会被记为%3A。 这一个编码形式叫做URL编码。在变量名和它的值之间利用间隔符号“=”分离。符号 (&)被用于将一个名字数值对与其它的名字数值对区分开来。一旦URL到达网络服务器,CGI程序将被触发,类似于本例中的myemailer.exe ,而且名字数值对的整个列表经由一个叫作QUERY_STRING的环境变量向前传递至CGI应用程序,它给出了在网络服务器与CGI应用程序通信的同时,服务器使用的环境变量列表)。QUERY_STRING的值将会是在 "?" 之后出现的任何值。在上例中,它会是:firstname=sabu&lastname=francis&email=sabu@somewhere.com

  37. 8.3.1.2 POST方法 • 在POST 方法中,使用各种交互式HTML元素将数值传送给Web服务器,这些交互式HTML指定了HTML FORM元素的有效的子元素( 例如INPUT,TEXTAREA等)。 这些数值被网络服务器接收,并由服务器使用stdout流传递至指定的的CGI程序。CGI程序依序读它的stdin流,以获取这些流包含的变量和数值。 正如前面所解释的,网络服务器的 stdout流是可读的,类似于被网络服务器调用的CGI应用程序的stdin流。 • 注意,即使在POST方法中,定义QUERY_STRING也是可以的。例如,我们能在应用程序名结尾的 "?" 之后定义一些参量,就像在前面所举的例子中显示的一样。因此,CGI程序既能从stdin中读取数据,也能从QUERY_STRING环境变量中读取数据。这一功能在我们的最后一例中(在cgitutorial.zip中的Example3.zip)被用于区分各种不同类型的POST处理过程。

  38. 8.3.1.3 GET方法和POST方法比较 • GET方法是可标记的。这意味着整个URL包含了所有需要被送往CGI程序的数据。缺点是以这种方式传送数据有一个上限 (大约1000字符)。另一个缺点是无论什么数据在被送往CGI程序的过程中都是可见的。 • POST方法的优点是它能处理大量信息。并且数据在传送过程中不易被查看(除非使用探测工具)。而且如果我们使用一个可靠的服务器,浏览器也已经可靠连接到网络服务器,此时即使使用探测工具可能也无法显示正向网络服务器传送的数据。POST方法的缺点是我们通常得在HTML中构造一个HTML FORM元素,并将这一FORM元素用正确的HTML交互式元素,比如INPUT,TEXTAREA等组装起来,以使POST方法正常工作。有的方法避免直接构建一个FORM元素,但是那将使HTML里面包含有结构庞大的Javascript程式。

  39. 8.3.1.4 URL编码 a) 非ASCII字符(代码值>128) 经由它们的URL八进制编码%xx进行编码。 b) 不能识别的或特殊的ASCII字符将通过他们的URL码编码。这些字符是包括: ‘~!#$%^&()+={}|[]\:";´<>?,/ TAB ,也就是除 @ * _ - 及 . (小数点)五个字符以外的所有字符。 c) 空格符将被编码成正号 (+) 或者%20。

  40. 8.3.2 解释信息流的高级CGI应用程序 • 我们可以将包含在cgitutorial.zip中的example2.zip文件解压到一个方便的目录中,并在此查找Visual Prolog文件。这个例子使用一个叫做BLAT的实用小程序 (一个免费的程序,和帮助文件一起包含在cgi-bin目录下) 邮寄表格的内容。我们能根据下面所给的描述写出一个这样的应用程序。 1) 首先,我们可以按照在本章例子example1创建过程所描述的步骤执行。这些步骤执行结束后,就要执行一附加步骤,使 CGI 程序能够接收来自网络服务器的输入。如前面所指出的,我们需要求助于包含在Visual Prolog中的PFC(Prolog基类)。右击项目树上的PFC 文件夹,会显示一个文件对话框。通过PFC文件夹进入CGI文件夹,点击cgi.pack。此时项目树中也应该显示出cgi.pack,然后重新构建程序。 以上步骤实现后,就有可能使用PFC谓词cgi::getParamList()获得所有经由网络服务器送至CGI程序的名字数值对。谓词智能化地剖析数据,不考虑数据被网络服务器传送时使用的是POST方法还是GET方法。

  41. 8.3.2 解释信息流的高级CGI应用程序 2) 双击example2.pro,增加以下谓词: class predicates assembleParams:(namedValue_list List,string Seed) ->string procedure(i,i). clauses assembleParams([],S)=S. assembleParams([H|T],OldSeed)=Result:- H=namedValue(N1,string(V1)), NewSeed=string::concatList([OldSeed,N1,"=",V1,"\n\n"]), !, Result=assembleParams(T,NewSeed).

  42. 8.3.2 解释信息流的高级CGI应用程序 3) 将run() 中的子句改变为如下的形式: run():- console::init(), OutStream = console::getConsoleOutputStream(), OutStream:setMode(stream::ansi(core::ansi)), stdIO::write("Content-type: text/html\n\n"), doIt(). 4) 增加一个新的谓词doIt() 如下所示:

  43. 8.3.2 解释信息流的高级CGI应用程序 class predicates doIt:(). clauses doIt():- trap(file5x::file_str("blatparams.txt",BlatParams),_,fail), PList=cgi::getParamList(), S=assembleParams(PList," "), file5x::filenameunique("abc",Unq), file5x::file_str(Unq,S), BlatCmd=string::concatList(["blat.exe ",Unq, "  ",BlatParams]), platformSupport5x::system(BlatCmd). doIt():- stdIO::write("Could not find the file blatparams.txt", " in the cgi-bin directory. Create this file"), stdIO::write(" with just one line (NO carriage return at the end", " of the line!), as shown in the example below:<BR><BR>"), stdIO::write("<PRE>-to sabu@archsfa.com -server archsfa.com -f", " sabu@somewhere.com</PRE><BR><BR>"), stdIO::write( "In the above line, replace sabu@archsfa.com with the email address", " of the person to whom the form is to be sent to."), stdIO::write(" Replace archsfa.com with the SMTP address", " that can be used, and replace sabu@somewhere.com"), stdIO::write( " with the 'From' address that is to be used for the transaction. " "All these addresses MUST be valid.<BR><BR>"), stdIO::write( " More parameters can be added to this file ", "(e.g. the subject to be used, etc.) if you understand the BLAT utility"), !.

  44. 8.3.2 解释信息流的高级CGI应用程序 5) 在程序中加入5xPlatformsupport.pack和5xFile.pack 。这一过程与在本章前面描述的过程一致。这两个程序包是编译CGI程序所必需的。 6) 调用建立过程。这时会出现一些对话框,询问在编译时是否包含其他包。回答“是”就表示全包含。

  45. 8.3.2 解释信息流的高级CGI应用程序 7) 让我们检查并试运行。与Example1不同,本例中的run()谓词非常小。它只输出标准的MIME类型text/html头和一个空白行,然后直接将控制权交给doit()谓词。这是必需的,因为doit() 有两个子句,第一个子句体是完成主要工作的,第二个子句在找不到此项目需要的配置文件时被执行。doit() 的第一行试图使用file5x:file_str/2谓词读取配置文件。如果找不到该文件,那么它将立刻失效并调用doit()的第二个子句。doit()的第二和第三行收集输入变量及其数值的列表(经由网络服务器传送),再从列表产生一个长的字串。这一字串被存储在cgi-bin目录下的一个专门文件中,并且这一文件的内容将被blat实用程序电子邮寄。前面提到的配置文件blatparams.txt,包含了文件内容被送达人的EMAIL地址。 8) 这一例子有很多优点。我们能在许多CGI程序环境中将这一程序作为通用的捕获应用程序,任意形式的输入都能被接受并邮寄给所选择的任何人。

  46. 8.3.3 信息从网络服务器到浏览器的传输 • 信息从Web服务器到浏览器的传输总是以单一流发生吗?不总是这样。只有最小的HTML文件,如在前面的例子中给出的那样,从网络服务器到浏览器的传送才是发生在一个流里。大多数的HTML文件嵌有其他的MIME类型,例如图像或Javascript代码。HTML元素,比如<SCRIPT SRC="...">,<IMGSRC="...">等触发和网络服务器的特殊连接。为显示或使用这些特殊的MIME类型,浏览器与网络服务器建立单独的连接。这就是为什么浏览器用一种多变的方式分别建立页面的各个部分(例如图像)的原因。如果需要,我们甚至可以为每一条信息流分别编写CGI应用程序。举例来说,我们能分别编写出传送Javascript代码给浏览器的CGI程序和用来传送图像的程序。当我们学到本章节最后线程化讨论板(threaded discussion board)的例子的时候,这将会是很有用的。

  47. 8.3.3 信息从网络服务器到浏览器的传输 • 但是我们有必要写这么多的CGI程序以操作一个HTML文件中的各种不同的信息流吗?没必要,确实不需要为浏览器页面的每个信息流编写独立的CGI程序。实现方法有很多,在最后一例Example3.zip中,我们将会了解到,如何创建一个使用QUERY_STRING来区别被送往浏览器的各种不同类型信息流的CGI应用程序。开始时,谓词run()将检查QUERY_STRING并转向执行依赖于传入数值的代码。因此,即使我们只写了一个可执行文件,因为执行动作按照QUERY_STRING给出的命令发生改变,所以它像是具有了5个不同的CGI程序。

  48. 8.3.4 CGI应用程序简评 • CGI应用程序几乎没有限度地扩充网络服务器的功能。惟一的缺点是CGI应用程序必须运行得非常快。如果它花太多时间处理并输出数据,网络服务器将会暂停应用程序并忽略任何CGI应用程序在暂停之后可能提供的输出。

  49. 8.3.5 取代CGI程序的候选方案 • 已经有尝试去改变规范,比如使用管道和套接字(pipes and sockets)。更高级的网络服务器有允许服务器本身扩展处理CGI流量的内建API 应用程序接口。这些扩展通常记为 DLL文件形式。这些措施全是为达到较高的速度。然而也带来了兼容性问题。 • 幸运的是,核心CGI规范事实上仍被所有网络服务器所遵守。因此,如果我们抵制住研究改变CGI的诱惑,并且坚持CGI主规范,那么我们将能写出可在各种网络服务器上使用的CGI 程序。

  50. 8.3.6 加速CGI应用程序 • cgitutorial.zip中的Example1.zip和Example2.zip例子完成了网络服务器端所做的所有数据处理。这包括数据的描述信息。通过描述信息,我们实际上可以在客户端的浏览器窗囗中查询所有HTML信息。在网络服务器端集成全部的HTML时常耗费大量时间。还有另一个缺点是:已集成的HTML不易再改变,除非重新编译 CGI程序本身。要避免这一缺点的一个非常简单的方法就是以Javascript的形式送原始的数据元到浏览器,并且让浏览器以最后显示的HTML形式,实际执行所有的信息描述。

More Related