目录
- 什么是 CGI?
- 环境准备
- 安装 Web 服务器
- 配置 Web 服务器以支持 CGI
- 编写你的第一个 C CGI 程序
- 编译和放置程序
- 设置执行权限
- 测试你的 CGI 程序
- 进阶示例:处理表单数据
- 排错与调试
什么是 CGI?
CGI (Common Gateway Interface) 是一种标准,它允许 Web 服务器(如 Apache 或 Nginx)执行一个外部程序,并将程序的输出结果返回给客户端的浏览器。

工作流程如下:
- 浏览器请求: 用户在浏览器中访问一个 URL,
http://your-server.com/cgi-bin/hello.cgi。 - 服务器识别: Web 服务器看到这个 URL 指向了一个可执行程序(在
cgi-bin目录下)。 - 服务器执行: 服务器启动这个 C 程序作为子进程来运行。
- 环境变量和标准输入: 服务器设置一系列环境变量(如
REQUEST_METHOD,QUERY_STRING等),并将客户端的数据(如表单数据)通过标准输入 传递给 C 程序。 - 程序处理: C 程序读取环境变量和标准输入,进行计算或处理。
- 标准输出: C 程序将 HTML 内容(或其他类型的内容)写入到标准输出。
- 服务器响应: Web 服务器捕获 C 程序的标准输出,并将其作为 HTTP 响应发送回浏览器。
- 浏览器显示: 浏览器接收到 HTML 内容并渲染显示给用户。
关键点:
- 环境变量: CGI 程序通过读取环境变量来获取请求信息。
- 标准输入: 用于接收 POST 请求的表单数据。
- 标准输出: 用于返回 HTTP 响应体(通常是 HTML)。
环境准备
我们将使用 Ubuntu 最常用的 Web 服务器 Apache。
a. 安装 Apache
打开终端,执行以下命令:

sudo apt update sudo apt install apache2
安装完成后,Apache 服务会自动启动,你可以通过访问 http://localhost/ 或 http://127.0.0.1/ 来确认安装是否成功(你会看到 Apache 的默认欢迎页面)。
b. 配置 Apache 以支持 CGI
默认情况下,Apache 可能没有启用 CGI 功能,我们需要修改它的配置文件。
-
启用
cgi模块: Apache 使用模块来扩展功能,我们需要启用cgi模块。sudo a2enmod cgi
这会创建一个指向
/etc/apache2/mods-enabled/cgi.load的符号链接。
(图片来源网络,侵删) -
配置 CGI 目录: 最安全的做法是将 CGI 程序存放在一个专门的目录中,通常是
/usr/lib/cgi-bin,Apache 默认配置中已经包含了对此目录的支持。让我们检查一下
/etc/apache2/sites-available/000-default.conf文件,确保其中有类似下面的配置段(通常默认就有):<Directory "/usr/lib/cgi-bin"> AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch AddHandler cgi-script .cgi Require all granted </Directory>Options +ExecCGI: 这是关键,它允许在这个目录中执行 CGI 脚本。AddHandler cgi-script .cgi: 告诉 Apache 所有以.cgi结尾的文件都应作为 CGI 程序处理。
-
重启 Apache 服务: 让配置生效。
sudo systemctl restart apache2
编写你的第一个 C CGI 程序
我们来创建一个简单的 CGI 程序,它的功能是在网页上打印 "Hello, World from C CGI!"。
创建一个文件,hello.c:
#include <stdio.h>
#include <stdlib.h>
int main() {
// 1. 打印 HTTP 响应头
// 这是至关重要的!必须以两个换行符结束。
// Content-Type 告诉浏览器我们返回的是什么类型的数据。
// 对于 HTML,它的值是 text/html。
printf("Content-Type: text/html\n\n");
// 2. 打印 HTML 内容到标准输出
// 这部分内容将被浏览器解析并显示。
printf("<html>\n");
printf("<head>\n");
printf(" <title>Hello from C CGI</title>\n");
printf("</head>\n");
printf("<body>\n");
printf(" <h1>Hello, World from C CGI!</h1>\n");
printf(" <p>This page is generated by a C program.</p>\n");
printf("</body>\n");
printf("</html>\n");
// 3. 正常退出程序
return 0;
}
代码解释:
printf("Content-Type: text/html\n\n");这是 最重要 的一行,它告诉浏览器接下来接收到的数据是 HTML 格式。必须有两个换行符\n\n,第一个结束响应头,第二个开始响应体。- 后续的
printf语句就是标准的 HTML 代码,它们被发送到标准输出,由 Apache 捕获并返回给浏览器。
编译和放置程序
-
编译 C 程序: 使用
gcc编译器将hello.c编译成一个可执行文件,我们需要链接一些 Apache 可能需要的库。gcc -o hello.cgi hello.c
-o hello.cgi: 指定输出的可执行文件名为hello.cgi。.cgi后缀是一个约定,方便识别。
-
放置到 CGI 目录: 将编译好的
hello.cgi文件复制到 Apache 配置的 CGI 目录中。sudo cp hello.cgi /usr/lib/cgi-bin/
使用
sudo是因为/usr/lib/cgi-bin/目录通常需要 root 权限才能写入。
设置执行权限
Web 服务器进程(通常是 www-data 用户)需要能够读取和执行你的 CGI 程序,必须给它设置正确的权限。
sudo chmod 755 /usr/lib/cgi-bin/hello.cgi
7(所有者): 读、写、执行5(组): 读、执行5(其他): 读、执行 这允许www-data用户执行这个脚本。
测试你的 CGI 程序
打开你的 Web 浏览器,访问以下 URL:
http://localhost/cgi-bin/hello.cgi
你应该能看到一个标题为 "Hello from C CGI" 的页面,内容是 "Hello, World from C CGI!"。
恭喜!你已经成功运行了你的第一个 C 语言 CGI 程序!
进阶示例:处理表单数据
CGI 更强大的功能在于处理用户通过表单提交的数据,我们来看一个简单的例子。
a. 创建一个 HTML 表单
创建一个文件 form.html (可以放在 Apache 的默认网站根目录 /var/www/html/ 下):
<!DOCTYPE html>
<html>
<head>CGI Form Example</title>
</head>
<body>
<h2>Enter your name</h2>
<form action="/cgi-bin/form_handler.cgi" method="get">
Name: <input type="text" name="username">
<input type="submit" value="Submit">
</form>
</body>
</html>
action="/cgi-bin/form_handler.cgi": 指定表单数据将被提交到form_handler.cgi这个 CGI 程序。method="get": 使用 GET 方法提交数据,数据会附加在 URL 后面(...?username=John)。
b. 编写处理表单的 C CGI 程序
创建 form_handler.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 一个简单的辅助函数,用于从 QUERY_STRING 中获取变量值
char* get_query_string_value(const char* query, const char* var) {
char* value = NULL;
char* pair = strtok((char*)query, "&");
while (pair != NULL) {
char* eq = strchr(pair, '=');
if (eq != NULL) {
*eq = '\0'; // 分割键和值
if (strcmp(pair, var) == 0) {
value = eq + 1;
break;
}
}
pair = strtok(NULL, "&");
}
return value;
}
int main() {
// 1. 打印 HTTP 响应头
printf("Content-Type: text/html\n\n");
// 2. 获取环境变量 QUERY_STRING
// 对于 GET 请求,表单数据会在这里
char *query_string = getenv("QUERY_STRING");
char *username = NULL;
if (query_string != NULL) {
username = get_query_string_value(query_string, "username");
}
// 3. 根据是否有数据生成不同的 HTML
printf("<html>\n");
printf("<head><title>Form Response</title></head>\n");
printf("<body>\n");
if (username != NULL && strlen(username) > 0) {
// URL 解码 (简化版,实际应用中应使用更健壮的库)
char *decoded_username = username;
for (int i = 0; decoded_username[i]; i++) {
if (decoded_username[i] == '+') {
decoded_username[i] = ' ';
}
}
printf("<h1>Hello, %s!</h1>\n", decoded_username);
} else {
printf("<h1>Error: No name provided.</h1>\n");
printf("<p><a href=\"/form.html\">Go back</a></p>\n");
}
printf("</body>\n");
printf("</html>\n");
return 0;
}
c. 编译、放置和设置权限
# 编译 gcc -o form_handler.cgi form_handler.c # 复制 sudo cp form_handler.cgi /usr/lib/cgi-bin/ # 设置权限 sudo chmod 755 /usr/lib/cgi-bin/form_handler.cgi
d. 测试
- 在浏览器中访问
http://localhost/form.html。 - 在输入框中输入你的名字("Alice"),然后点击 "Submit"。
- 浏览器会跳转到
http://localhost/cgi-bin/form_handler.cgi?username=Alice,并显示 "Hello, Alice!"。
排错与调试
如果程序没有按预期工作,这里是常见的排查步骤:
- 检查权限: 确保文件在
/usr/lib/cgi-bin/目录下,并且有755权限 (sudo chmod 755 ...)。 - 检查编译: 确保程序没有编译错误,运行
./hello.cgi(在本地测试) 看看是否能正常输出 HTML。 - 查看 Apache 错误日志: 这是最有用的工具!CGI 程序的
stderr(标准错误)会被重定向到 Apache 的错误日志中。- 查看日志命令:
tail -f /var/log/apache2/error.log
- 在浏览器中访问你的 CGI 脚本,然后立即查看这个日志文件,你很可能会看到 C 程序中的
printf错误信息(比如忘记打印Content-Type头),或者程序崩溃的原因(比如段错误)。
- 查看日志命令:
- 检查 Content-Type 头: 确保第一行响应是
printf("Content-Type: text/html\n\n");,并且有两个换行符。 - 简单测试: 先确保最简单的 "Hello, World" CGI 能工作,再逐步添加复杂功能。
希望这份详细的指南能帮助你在 Ubuntu 上成功使用 C 语言进行 CGI 开发!
