CGI (Common Gateway Interface) 是 Web 服務器與外部程序交互的標準協議,將靜態頁面變為動態交互應用。雖然現代框架(FastCGI、uWSGI、Node.js 等)性能更高,但 CGI 仍是理解 Web 後端本質的最佳切入點。本文涵蓋協議原理、服務器配置、環境變量、C 語言開發實例及 Apache 部署全流程。
| 變量 | 含義 | 示例 |
| REQUEST_METHOD | GET/POST | POST |
| QUERY_STRING | GET 參數字符串 | m=3&n=4 |
| CONTENT_LENGTH | POST 數據長度 | 27 |
| CONTENT_TYPE | POST 數據類型 | application/x-www-form-urlencoded |
| HTTP_USER_AGENT | 客戶端標識 | Mozilla/5.0... |
| REMOTE_ADDR | 客戶端 IP | 192.168.1.100 |
| SERVER_NAME | 服務器主機名 | localhost |
Apache CGI 配置(以 USBWebServer 為例)
# httpd.conf
ScriptAlias /cgi-bin/ "{rootdir}/cgi-bin/"
AllowOverride None
Options ExecCGI
Order allow,deny
Allow from all
AddHandler cgi-script .exe .pl .cgi
將編譯好的 `.exe` 放入 `cgi-bin` 目錄,瀏覽器訪問 `https://127.0.0.1:8080/cgi-bin/index.cgi`。
C 語言 CGI 開發實戰三部曲
1. 入口頁面 `index.html`(表單演示)
2. GET 處理 `mult.cgi`(乘法計算器)
#include
#include
int main() {
printf("Content-Type:text/html\n\n"); // 必須:HTTP Header 結束雙換行
printf("乘法結果乘法結果
");
char *data = getenv("QUERY_STRING");
long m, n;
if (!data) printf("錯誤:無輸入數據");
else if (sscanf(data, "m=%ld&n=%ld", &m, &n) != 2)
printf("
錯誤:參數格式非法");
else
printf("
%ld * %ld = %ld", m, n, m * n);
printf("");
return 0;
}
3. POST 處理 `collect.cgi`(留言存儲)
#include
#include
#define MAXLEN 80
#define DATAFILE "../data/data.txt"
void url_decode(char *src, char *dst) { // 簡易 URL 解碼
for (; *src; src++, dst++) {
if (*src == '+') *dst = ' ';
else if (*src == '%') {
int code; sscanf(src+1, "%2x", &code); *dst = code; src += 2;
} else *dst = *src;
}
*dst = '\0';
}
int main() {
printf("Content-Type:text/html\n\n");
printf("Response");
char *lenstr = getenv("CONTENT_LENGTH");
long len = lenstr ? atol(lenstr) : 0;
if (len <= 0 || len > MAXLEN) {
printf("提交錯誤");
} else {
char input[MAXLEN+10], data[MAXLEN+10];
fgets(input, len+1, stdin); // 從 stdin 讀取 POST 體
url_decode(input + 5, data); // 跳過 "data="
FILE *f = fopen(DATAFILE, "a");
if (f) { fputs(data, f); fclose(f); printf("
留言已保存"); }
else printf("
系統錯誤");
}
printf("");
return 0;
}
4. 查看留言 `viewdata.cgi`
#include
#include
#define DATAFILE "../data/data.txt"
int main() {
FILE *f = fopen(DATAFILE, "r");
if (!f) {
printf("Content-Type:text/html\n\n無法打開文件");
return 0;
}
printf("Content-Type:text/plain\n\n"); // 純文本輸出
int ch;
while ((ch = getc(f)) != EOF) putchar(ch);
fclose(f);
return 0;
}
編譯部署清單
- 安裝 GCC(MinGW / Cygwin / Linux 原生)
- `gcc mult.c -o mult.exe` 等生成可執行文件
- 複製 `.exe` 到 Apache `cgi-bin` 目錄
- 確保 `data.txt` 目錄可寫(Windows 需檢查權限)
- 瀏覽器測試各功能
CGI 與現代替代方案對比