# 3.4.1 CGI
### 3.4.1 CGI
CGI即**通用网关接口(Common Gateway Interface)**,1993年由美国NCSA(National Center for Supercomputing Applications)发明。它具有简单易用、语言无关的特点。虽然今天已经少有人直接使用CGI进行编程,但它仍被主流的Web服务器,如Apache、IIS、Nginx[1](#fn_1)等,所广泛支持。另外,它还影响了其他一些服务器端技术,如PHP、Python WSGI、Ruby Rack等——在这些技术里你都能看到CGI的影子。所以它仍然值得学习。
先来看一个最简单的CGI程序[2](#fn_2):
```
#!/usr/bin/perl
print "Content-type: text/plain\n", "\n";
print "Hello, CGI!";
```
把这个程序保存到文件hello.pl,并假设它对应的URL是`http://localhost/cgi-bin/hello.pl`。在浏览器中访问这个URL,你就能看到程序的输出结果——一个普通文本:
```
Hello, CGI!
```
在前面[HTTP - 服务器应答](response.html)一节我们已经了解了HTTP应答的格式,对照一下,你会发现这个CGI程序的输出正是如此:首先是若干头部(header),一个一行(这里仅有一个Content-Type头);接着是一个空行(注意Content-Type这一行结尾输出了两个”\\n”:第一个是头部的换行,第二个是分隔头部和正文的空行);最后是消息正文。与之前不同的是,这里我们没有输出应答状态行(Status Line)——这有一些特别:如果CGI程序没有指明,缺省的状态代码是200;如果想返回其他代码,需要用到一个特殊的Status头部(header),如:
```
print "Status: 404 Not found\n";
```
CGI程序可以动态产生任何内容,只要按照HTTP应答的格式向标准输出(stdout)设备输出这些内容即可。另外,CGI程序也可以由任何语言来编写,上面的例子只是以Perl为例,你还可以用Python、Ruby、BASH脚本……,以及编译好的C/C++程序。
在上面的例子中我们还没有谈到程序的输入(input)。CGI程序使用环境变量作为输入。下面的例子展示了这一点:
```
#!/usr/bin/perl
print "Content-type: text/plain\n", "\n";
foreach my $key (sort keys %ENV) {
print "$key => $ENV{$key}\n";
}
```
这个CGI程序把它的环境变量和值都打印了出来。假设它对应的URL是`http://localhost/cgi-bin/env.pl`。我们在浏览器中访问`http://localhost/cgi-bin/env.pl?name=Bob`,会得到类似如下的结果:
```
GATEWAY_INTERFACE => CGI/1.1
HTTP_ACCEPT => text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
HTTP_ACCEPT_ENCODING => gzip, deflate, sdch
HTTP_ACCEPT_LANGUAGE => zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4
HTTP_CACHE_CONTROL => max-age=0
HTTP_CONNECTION => keep-alive
HTTP_COOKIE => ...
HTTP_HOST => localhost
HTTP_UPGRADE_INSECURE_REQUESTS => 1
HTTP_USER_AGENT => Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36
PATH => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
QUERY_STRING => name=Bob
REMOTE_ADDR => 10.0.0.9
REMOTE_PORT => 50497
REQUEST_METHOD => GET
REQUEST_SCHEME => http
REQUEST_URI => /cgi-bin/env.pl?name=Bob
SCRIPT_FILENAME => /var/www/cgi-bin/env.pl
SCRIPT_NAME => /cgi-bin/env.pl
SERVER_ADDR => 10.0.0.8
SERVER_ADMIN => webmaster@localhost
SERVER_NAME => localhost
SERVER_PORT => 80
SERVER_PROTOCOL => HTTP/1.1
SERVER_SIGNATURE => <address>Apache/2.4.7 (Ubuntu) Server at ubuntu-vm Port 80</address>
SERVER_SOFTWARE => Apache/2.4.7 (Ubuntu)
...
```
其中,HTTP\_开头的变量都是请求头(request header),其他大部分都是服务器提供的元变量(meta variable),如SERVER\_NAME,REQUEST\_URI和REMOTE\_ADDR等,以及少量关于主机的环境变量,如PATH。这些变量的含义大都不言自明,在此不一一解释。值得指出的是,我们在URL请求里的查询部分,即”?name=Bob”,可以通过QUERY\_STRING变量得到。此外,如果请求含有消息正文(message body),如前面“资源与方法”一节的POST的例子,我们可以通过读取标准输入设备(stdin)来得到它。
总之,CGI程序通过环境变量和标准输入获得请求的各种参数信息,通过标准输出返回应答;服务器并不关心CGI程序是用什么语言编写的,它仅通过环境变量和标准输入、输出与CGI程序交互。
每当有一个请求对应到一个CGI程序时,服务器就启动一个进程执行这个CGI程序。因此CGI程序对主机的资源消耗比较大(想想如果有1000个并发请求会怎么样),同时它的响应速度也会比较慢(进程的启动比较花时间)。所以人们开始寻找CGI的替代者,这导致了FastCGI等技术的出现。关于CGI的更多信息,可参考[https://en.wikipedia.org/wiki/Common\_Gateway\_Interface](https://en.wikipedia.org/wiki/Common_Gateway_Interface)。
> 1. 严格来说Nginx不直接支持CGI,但它支持CGI的变体FastCGI,所以实际上仍然算是支持的。参考:<https://www.nginx.com/resources/wiki/start/topics/examples/simplecgi/>[↩](#reffn_1 "Jump back to footnote [1] in the text.")
> 2. 以Apache服务器为例,请参考它的文档来设置好CGI的运行环境: <http://httpd.apache.org/docs/current/howto/cgi.html>[↩](#reffn_2 "Jump back to footnote [2] in the text.")
- 前言
- 1 Web概述
- 1.1 什么是Web
- 1.2 超文本和超链接
- 1.3 URL
- 1.4 DNS
- 1.5 HTTP
- 1.5.1 客户端请求
- 1.5.2 服务器应答
- 1.5.3 进一步了解HTTP
- 1.6 HTTPS
- 2 Web浏览器
- 2.1 HTML
- 2.1.1 文档类型声明
- 2.1.2 标签和属性
- 2.1.3 文档结构
- 2.1.4 DOM
- 2.1.5 进一步了解HTML
- 2.2 CSS
- 2.2.1 样式与样式表
- 2.2.2 样式表语法
- 2.2.3 级联样式表
- 2.2.4 进一步了解CSS
- 2.3 JavaScript
- 2.3.1 script标签
- 2.3.2 操纵DOM
- 2.3.3 jQuery
- 2.3.4 进一步了解JavaScript
- 2.4 Ajax
- 2.5 移动设备与响应式Web设计
- 3 Web服务器
- 3.1 方法与资源
- 3.2 状态代码
- 3.3 静态内容与动态内容
- 3.4 编程语言与技术
- 3.4.1 CGI
- 3.4.2 PHP
- 3.4.3 Java
- 3.4.4 Python
- 3.4.5 Ruby
- 3.4.6 Node.js
- 3.5 RESTful Web API
- 3.6 服务器架构
- 3.7 Web缓存
- 3.8 服务器推送
- 4 数据库
- 4.1 关系型数据库
- 4.2 NoSQL数据库
- 5 Web服务器的其他组件
- 5.1 Cron
- 5.2 消息队列
- 5.3 邮件服务器
- 6 开发工具与技术
- 6.1 Git
- 6.1.1 Git基础操作
- 6.1.2 Git基本原理
- 6.1.3 进一步了解Git
- 6.2 敏捷开发