CGI (Common Gateway Interface) 定義了Web服務器調用外部可執行程序的標準接口協議。其本質是進程間通信:
瀏覽器發送HTTP請求
↓
Web服務器解析請求 → 設置環境變量 + 標準輸入寫入POST數據
↓
fork/exec 啟動CGI程序
↓
CGI程序讀取環境變量/標準輸入 → 業務邏輯處理
↓
CGI程序寫入標準輸出 → Web服務器捕獲
↓
Web服務器封裝HTTP響應返回瀏覽器
CGI程序可用任何語言編寫,**C語言優勢**在於:編譯型、執行速度快、二進制不可篡改(安全性高)、內存佔用小——極適合高併發、資源受限環境。
| 通道 | 用途 | 典型場景 | C語言訪問方式 |
|---|---|---|---|
| 標準輸入 (stdin) | 接收POST請求體數據 | 表單提交、文件上傳、大數據傳輸 | getchar(), fread(), read(0, ...) |
| 環境變量 | 傳遞請求元數據 | 請求方法、查詢字符串、客戶端IP、認證信息、內容長度/類型 | getenv("VAR_NAME") |
| 標準輸出 (stdout) | 發送響應內容 | HTML/JSON/XML/圖片/二進制流 | printf(), putchar(), fwrite(), write(1, ...) |
| 變量名 | 含義 | 示例 |
|---|---|---|
REQUEST_METHOD | 請求方法 | GET / POST |
CONTENT_LENGTH | POST數據字節數 | 27 |
CONTENT_TYPE | POST數據MIME類型 | application/x-www-form-urlencoded |
QUERY_STRING | GET查詢字符串 / POST數據(某些服務器) | name=zhang&age=25 |
HTTP_REFERER | 來源頁面URL | https://example.com/form.html |
REMOTE_ADDR | 客戶端IP | 192.168.1.100 |
SCRIPT_NAME | CGI腳本路徑 | /cgi-bin/process.cgi |
表單數據以 application/x-www-form-urlencoded 格式傳輸:
name1=value1&name2=value2&name3=value3...
解析規則:
& 分割鍵值對= 分割鍵與值+ → 空格%XX → 十六進制ASCII碼對應字符 (如 %20 → 空格,%3D → =)#include <stdio.h>
#include <stdlib.h>
int main() {
char *clen = getenv("CONTENT_LENGTH");
int n = clen ? atoi(clen) : 0;
printf("Content-Type: text/plain\n\n"); // 必須雙換行分隔頭體
for (int i = 0; i < n; i++)
putchar(getchar());
putchar('\n');
fflush(stdout);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int htoi(char *s) { // 兩位十六進制轉整數
char *digits = "0123456789ABCDEF";
if (islower(s[0])) s[0] = toupper(s[0]);
if (islower(s[1])) s[1] = toupper(s[1]);
return 16 * (strchr(digits, s[0]) - strchr(digits, '0')) +
(strchr(digits, s[1]) - strchr(digits, '0'));
}
int main() {
char *clen = getenv("CONTENT_LENGTH");
int n = clen ? atoi(clen) : 0;
printf("Content-Type: text/plain\n\n");
for (int i = 0; i < n; i++) {
int c = getchar();
int is_eq = 0;
switch (c) {
case '&': c = '\n'; break; // 鍵值對分隔 → 換行
case '+': c = ' '; break; // + → 空格
case '%': { // %XX → 字符
char s[3] = {getchar(), getchar(), 0};
c = htoi(s);
i += 2;
break;
}
case '=': c = ':'; is_eq = 1; break; // = → : 並標記後加空格
}
putchar(c);
if (is_eq) putchar(' ');
}
putchar('\n');
fflush(stdout);
return 0;
}
#include <stdio.h>
#include <string.h>
int main() {
printf("Content-Type: text/html\n\n"); // 告訴瀏覽器這是HTML
printf("\nCGI生成的HTML頁面 \n\n");
printf("這是由C語言CGI程序動態生成的HTML頁面
\n");
printf("
\n");
printf("返回首頁\n");
printf("\n\n");
fflush(stdout);
return 0;
}
注意:字符串中雙引號需轉義 \",因外層已用雙引號包裹。
cgi-bin/ 目錄,需可執行權限 (chmod 755)。./program.cgi,手動設置環境變量模擬請求:
export REQUEST_METHOD=POST
export CONTENT_LENGTH=27
export CONTENT_TYPE=application/x-www-form-urlencoded
echo "name=zhang&age=25" | ./program.cgi
/var/log/apache2/error.log)Content-Type 頭且緊跟 空行 (\n\n)FastCGI / SCGI 避免每請求 fork/exec 開銷| 維度 | C語言CGI | Perl/Python CGI |
|---|---|---|
| 執行速度 | 極快 (原生機器碼) | 較慢 (解釋執行) |
| 字符串處理 | 手動管理,易出錯 | 內置強大正則、高級數據結構 |
| 開發效率 | 低 (樣板代碼多) | 高 (語法簡潔、庫豐富) |
| 部署依賴 | 無 (靜態鏈接) | 需解釋器環境 |
| 適用場景 | 高併發、嵌入式、實時、安全敏感 | 快速迭代、複雜文本處理、原型驗證 |
建議:核心高性能模塊用C,業務邏輯層用腳本語言,或引入 CGI Library (cgic)、libfcgi 簡化C開發。
C語言CGI開發雖需手工處理較多細節(環境變量、URL解碼、MIME頭),但掌握其核心機制後,可構建極致高效、安全可控的Web後端。本文提供的完整代碼模板可直接用於項目起步。隨著業務增長,建議遷移至FastCGI架構或現代Web框架,但CGI作為「萬物之源」,理解它對任何後端開發者都至關重要。