基于网络的午餐订购系统

作者:Cheng-Chai Ang

或许这篇文章应该被命名为“我是如何发现 Python 并抛弃其他一切的”。我一直想编写基于网络的应用程序,但总觉得入门非常困难。因此,在拖延多年之后,我终于开始编写我的第一个应用程序。我的工作需要一个办公室内部应用程序,其中一些值需要在网页上提示。这些值被发送到一个 CGI 脚本,通过 SQL 数据库交叉验证,通过套接字分发到一个等待进程,并将结果发送回网页。

幸运的是,我偶然发现了一种名为 Python 的脚本语言。我当时正在阅读最新一期的《Linux Journal》(1999 年 12 月刊),其中他们采访了 Eric Raymond,他提到他现在只用 Python 编程。那时,我已经用 Perl 实现上述系统一天了,但还没有完全完成。如果 Python 对 Eric 来说足够好,那么就值得一试。

好吧,我只用了两个多小时就完成了我想做的事情。这是使用一种我在两个小时前才听说的语言。冒着失去我的专业优势的风险,我想与他人分享 Python 是多么容易使用,尤其是进行 CGI(以及几乎所有其他事情)。由于上述应用程序过于技术性和枯燥,不适合实际操作(而且我可能会被我的雇主起诉),我决定进行另一个更有趣的练习。

问题描述

工作地点位于一个半偏远地区(就饮食而言,除了隔壁的地方,那里的食物很棒,但每天在那里吃午饭有点贵),所以组织了每周一次的外卖午餐送到我们这里。每个参与者轮流组织午餐订单。由于分布在三层楼,这真是一件苦差事,没有人期待去做这件事。在我看来,基于网络的订购系统是显而易见的解决方案,但由于以前没有做过任何 CGI 编程,这似乎非常令人不知所措。其他人似乎并不在意。但是编写 CGI 网络系统可能非常简单,特别是当可以使用 Python 完成时。(好吧,Perl 大师可能会不同意,但这就是重点,即 Perl 大师与 Python 新手!)

初始需求

我大致知道我想要它的结构。会有一个网页,其中有一个下拉列表,列出餐厅菜单,并且通过单击提交按钮,一封包含个人</#146>订单的电子邮件将被发送给指定的午餐组织者。

根据传闻和在网络上进行的一些粗略研究,我决定使用以下工具

  • Javascript 用于客户端(网页)

  • Python 用于服务器端

  • Apache 用于 Web 服务器,它与 Linux 一起分发(嗯,它是与我的 Red Hat Linux 6.2 版本一起分发的);如果有人有兴趣,也有 Windows 版本

  • Linux 用于 Web 服务器操作系统

在设计网页时,我决定保持相当简单:一个带有单选按钮的下拉框(见图 1)。

A Web-Based Lunch Ordering System

图 1. lunch.html 的快照

我本可以使用一些 HTML 编辑器,但考虑到我无法应付学习另一个新软件包,所以我手工完成了它。由于我想做的事情并不复杂,手工方法证明是足够的。

使用 Linux 安装 Web 服务器很容易。当我在安装 Linux 时,安装 Apache 的选项被选中了。当我在 Netscape 中输入 localhost 作为 URL 时,它显示了 Apache 页面,并显示消息说如果我看到该页面,一切都很好!呜呼...目前为止一切顺利。(有关更多详细信息,请参阅 https://apache.ac.cn/)。您可能需要成为 root(超级用户)才能进行安装。

使用 Javascript 编写网页似乎是半显而易见的。有几个函数用于数据输入验证(ValidLength()ValidEmail())。MenuHeader() 显示页面的标题部分。每次调用 MenuEntry() 都会显示一个输入行。在本例中,它被调用了四次,午餐订单中的每个项目调用一次(见列表 1)。

列表 1

最棘手的行将是 ON-SUBMIT 语句

<FORM NAME="order" onSubmit="return Validate();"
    ACTION="https:///cgi-bin/lunch.cgi"
METHOD="POST">

网页可以通过两种方式与 CGI 脚本通信:GETPOST。简而言之,GET 将信息作为 URL 的一部分发送(即,您可能在 Internet 冲浪中看到过一些类似于 https:///script.cgi?param1=value1&param2=value2 的 URL)。当使用 POST 时,表单信息通过标准输入发送,即 CGI 脚本需要读取标准输入,然后解析输入以分离出各种参数。

人们普遍认为 POST 更好(更健壮,不受所用 shell 的最大字符数限制)。用于提取数据的方法因使用 POST 还是 GET 而异,但 Python 会对您隐藏这一点(这很好)。

通过 Web 服务器查看 lunch.html

然后我将 lunch.html 文件放在目录 /home/httpd/html 中

$ cp lunch.html /home/httpd/html

(这是 Apache 查找 html 文件的默认位置。可以配置为在其他位置查找。)完成此操作后,您可以通过使用 Netscape(或任何浏览器)浏览 https:///lunch.html 来查看 lunch.html 的外观。

使用 Python 编写 CGI 脚本,Python 与 Red Hat Linux 发行版一起分发(参见 https://pythonlang.cn/)。在查阅也随系统提供的 Python 文档后,我的第一个脚本看起来像列表 3 中所示的脚本。它本质上是 Python 文档中找到的示例的修改版本。要使用此脚本,您需要将 HTML 文件中 ACTION 语句中指定的 CGI 脚本指向此脚本。也就是说,将 ACTION 语句中指定的 cgi 脚本从 lunch.cgi 更改为 first.cgi。

测试安装

然后我将 first.cgi 复制到目录 /home/httpd/cgi-bin 中

$ cp first.cgi /home/httpd/cgi-bin

本质上,我询问了表单发送到脚本的所有变量,并将它们打印出来。所有打印的输出都将由浏览器显示。

#-----------------
 1 #!/usr/bin/env python
 2 # first.cgi
 3 import cgi                                   # import the cgi module
 4
 5 print "Content-Type: text/plain\n\n"       # necessary for the
browser
 6
 7 lunchForm = cgi.FieldStorage()               # retrieve the values
 8
 9 for name in lunchForm.keys():
10     print "Key= " + name + " Value= " +
lunchForm[name].value + " "
11
12 print "bye."
#-------------
当单击 lunch.html 页面上的 Go 按钮并激活 first.cgi 脚本时,返回到 Web 浏览器的输出看起来像图 2 中所示。

A Web-Based Lunch Ordering System

图 2. 脚本 first.cgi 的输出

您会注意到 CGI 脚本中找到的键与我在 lunch.html 中使用的变量相对应。

一旦我让这个简单的脚本工作起来,我就扩展它以执行我想要的操作(见列表 3)。Python 代码非常简单明了。它导入 CGI 模块,然后调用 CGI 的成员函数 FieldStorage()。信息是使用 GET 还是 POST 方法发送对您是隐藏的。这就是检索网页发送的所有信息的方式。然后可以通过访问 lunchForm 来提取信息。

列表 2

然后通过一系列写入 sendmail(UNIX sendmail 邮件传输代理)来构建发送邮件的正文。我决定将午餐订单邮寄给用户 lunch@localhost。可以在文件 /etc/aliases 中插入别名

lunch:          chai@localhost

其中用户 chai@localhost 正在组织订单。这样,如果午餐组织者发生更改,则需要更改文件 /etc/aliases,而不是 CGI 脚本。(需要运行 newaliases 才能使对 /etc/aliases 的更改生效)。

很简单,是吧?好吧,情况可能会更糟。

将所有内容连接在一起

然后我将 lunch.cgi 复制到目录 /home/httpd/cgi-bin 中

$ cp lunch.cgi /home/httpd/cgi-bin

我打开 Netscape,输入 https:///lunch.html 作为 URL,填写表单,选择我的订单并单击“Go”。

稍后,收到一封概述订单的电子邮件。

以下是 CGI 脚本发送的午餐订单的收到的电子邮件的样子

>From nobody@localhost  Wed Apr 26 11:01:50 2000<\n>
Delivered-To: ccang@localhost
Date: Wed, 26 Apr 2000 11:01:48 +1000
To: lunch@localhost
From: chai <calcium@altavista.net>
Subject: loi loi
Sender: nobody@localhost
SourceIP 194.118.1.1
calcium@altavista.net
Wed Apr 26 11:01:01 GMT+1000 (EST) 2000
chai wants
1. L39 with Steamed rice.
2. NONE with NA rice.
3. NONE with NA rice.
4. NONE with NA rice.
特殊说明:请做得格外美味!

图 3 显示了发送请求后网页的外观。

A Web-Based Lunch Ordering System

图 3. 完成午餐订单后生成的网页快照

结论

在线系统比在废纸上写订单的方法更好吗?这值得商榷,但它肯定更有趣(至少对我而言)。

改进?该网页面向个人下单,而不是为多人订购的人。事后看来,网页本可以考虑到后者进行布局,并且作为前者的超集,也将满足这些要求。一个简单的折衷方案可以是设置一个倍数框,这将允许一个人在每个订单行中订购同一道菜的多份。在当前的方案中,这仍然只允许每个电子邮件四个不同的订单。那么设为 10?20?绳子有多长?(改写以使其更险恶)。一个留给读者的设计问题。

我想我也可以将其连接到 SQL 数据库(http://www.mysql.org/),并打印出特定人员过去订单的直方图。使用数据库的副产品是可以打印出报告,例如,本周要订购什么。

我想如果大家有足够的兴趣,并且我有足够的时间,我将为该系统添加第二部分,其中 CGI 脚本将与 SQL 数据库交互并返回 HTML 代码以显示频率列表。并且,也许,还会进行一些 cookie 交互。

最后,就我个人而言,我已经看到了未来,那就是 Python。去了解一下吧(还有 JPython!)!

资源

感谢 Python 的简洁性,Cheng-Chai Ang (calcium@ozemail.com.au) 几乎立即从一名 Python 新手程序员成长为一名可以完成有用的(有时是非平凡的)工作的 Python 新手程序员。他为 Carbonated Software Pty, Ltd. 工作,并在从事了十年 C++ 之后,最近开始从事 JSP/Java servlets。

加载 Disqus 评论