CGI 是網頁伺服器與外部程式之間最早的溝通規範:訪客送出表單,伺服器啟動一支程式處理,程式把結果印成 HTML 回傳。1990 年代所有「會動」的網頁都靠它,今天它幾乎完全被 FastCGI、PHP-FPM 與各語言的應用伺服器取代。這篇文章說明 CGI 是什麼、怎麼運作、用 Perl 與 Python 各寫一支範例,然後回答兩個實務問題:為什麼它被淘汰、舊主機的 cgi-bin 該怎麼處理。本文屬於《網頁程式語言》系列,總覽見〈網頁程式設計是什麼〉。
一、CGI 是什麼?
CGI(Common Gateway Interface,通用閘道介面)是一套規範,定義網頁伺服器如何把 HTTP 請求的資料交給外部程式、再把程式的輸出當成回應送回瀏覽器。它不是程式語言:任何能讀環境變數、寫標準輸出的語言都能寫 CGI 程式,Perl、Python、C、shell 都可以。
CGI 於 1993 年由 NCSA 提出,2004 年以 RFC 3875 正式文件化。它解決的問題很單純:早期網頁伺服器只會送靜態檔案,CGI 讓伺服器能「呼叫一支程式來產生頁面」,動態網頁從此開始。慣例上這些程式放在網站的 cgi-bin 目錄,副檔名常是 .cgi 或 .pl。
二、CGI 怎麼運作?四個步驟
- 瀏覽器送出請求:例如提交一張表單到
/cgi-bin/form.cgi。 - 伺服器啟動一支新程序:Apache 等伺服器把請求資訊放進環境變數(
REQUEST_METHOD、QUERY_STRING、REMOTE_ADDR等),POST 的內容則從標準輸入送給程式。 - 程式處理並輸出:程式讀取資料、做運算或查資料庫,先印出至少一行 HTTP 標頭(
Content-Type: text/html)、一個空行,再印出 HTML。 - 程序結束,伺服器回傳:伺服器把程式的標準輸出原樣送給瀏覽器,然後這支程序就結束了。下一個請求再從頭啟動一支。
「每個請求啟動一支新程序」正是 CGI 最大的優點也是致命缺點:簡單、語言無關,但流量一大,光是不斷啟動程序就會拖垮伺服器。這一層架構在網頁伺服器與應用程式伺服器的分工中就能看出演進的方向。
三、CGI 程式範例:Perl
Perl 是 CGI 時代的主流語言,以下範例顯示一張表單並回應輸入的姓名。Perl 語言本身的語法見〈Perl 是什麼〉。
#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use HTML::Entities;
my $q = CGI->new;
my $name = $q->param('name') // '';
print $q->header(-type => 'text/html', -charset => 'UTF-8');
print <<"HTML";
<!DOCTYPE html>
<html lang="zh-Hant">
<body>
<h1>CGI 表單處理</h1>
<form method="post" action="/cgi-bin/form.cgi">
姓名:<input type="text" name="name">
<input type="submit" value="送出">
</form>
HTML
if ($name ne '') {
print '<p>您輸入的姓名是:', encode_entities($name), '</p>';
}
print "</body></html>\n";
兩個和舊教材不同的地方:header 指定了 UTF-8,中文才不會變亂碼;輸出使用者資料前用 encode_entities 轉義,否則對方輸入一段腳本就會在頁面執行。舊 CGI 程式普遍沒做這件事,是它們留下的主要資安問題。
四、CGI 程式範例:Python
同一件事用 Python 寫如下。注意 Python 內建的 cgi 模組已在 3.13 版移除,範例改用標準庫的 urllib.parse 自行解析。
#!/usr/bin/env python3
import os, sys, html
from urllib.parse import parse_qs
length = int(os.environ.get("CONTENT_LENGTH") or 0)
body = sys.stdin.read(length) if length else ""
data = parse_qs(body) if os.environ.get("REQUEST_METHOD") == "POST" else parse_qs(os.environ.get("QUERY_STRING", ""))
name = data.get("name", [""])[0].strip()
print("Content-Type: text/html; charset=UTF-8")
print()
print("<!DOCTYPE html><html lang='zh-Hant'><body>")
print("<h1>CGI 表單處理</h1>")
print('<form method="post" action="/cgi-bin/form.py">')
print('姓名:<input type="text" name="name"> <input type="submit" value="送出">')
print("</form>")
if name:
print(f"<p>您輸入的姓名是:{html.escape(name)}</p>")
print("</body></html>")
看得出 CGI 程式的骨架與語言無關:讀環境變數與標準輸入、印標頭、空一行、印 HTML。這也是為什麼它在教學上仍有價值,它把 HTTP 的請求與回應攤在眼前,沒有任何框架遮住。
五、CGI 程式要處理的三種資料
- 請求資料:GET 的參數在
QUERY_STRING環境變數,POST 的內容在標準輸入,長度由CONTENT_LENGTH告知。 - 環境變數:訪客 IP(
REMOTE_ADDR)、瀏覽器字串(HTTP_USER_AGENT)、請求方法與路徑等,RFC 3875 有完整清單。 - 輸出:至少一行標頭加空行,之後是內容;忘了空行是新手最常見的錯誤,結果會是伺服器回 500。
六、為什麼 CGI 被淘汰?替代方案是什麼
問題只有一個:每個請求啟動一支新程序太慢、太耗資源。解法沿著「讓程式常駐」這條線演進:
| 方案 | 做法 | 代表 |
|---|---|---|
| CGI | 每個請求啟動一支程序,結束即釋放 | cgi-bin 裡的 Perl、Python 程式 |
| 伺服器內嵌模組 | 直譯器直接載入伺服器程序內 | mod_php、mod_perl |
| FastCGI | 程式常駐、伺服器透過 socket 轉送請求 | PHP-FPM(現代 PHP 主機的標準) |
| 應用程式伺服器 | 語言自己的伺服器常駐,前面用 Nginx 反向代理 | WSGI/ASGI(Python)、Tomcat(Java)、Kestrel(.NET)、Node.js |
所以今天說「動態網頁」,實際跑的是表中後三種架構;PHP 之所以能在 2000 年代取代 Perl CGI,很大一部分就是它從一開始就以伺服器模組的形式執行,不必為每個請求付啟動成本。
七、舊主機的 cgi-bin 該怎麼處理
網站改版盤點時,我們對 cgi-bin 的原則是「先確認還有沒有人在用,再決定重做或下線」,不搬遷。
- 查存取日誌:一個月內沒有任何請求打到 cgi-bin 的程式,直接下線,舊網址回 410 或 301 到對應的新功能頁。
- 還在用的功能(最常見是表單寄信):改用現有網站系統的模組重做,不要把 CGI 程式搬到新主機;新主機多半沒有啟用 CGI,也缺少舊程式依賴的模組。
- 資安優先:無法確認有做輸入驗證的 CGI 程式,寧可先停用。被拿來寄垃圾信或植入內容的舊表單程式,會連帶讓整個網域的信譽與排名受損。
- 不要忘記搜尋引擎:cgi-bin 的網址若曾被索引,下線時要做好轉址,作法見〈301 與 302 轉址教學〉。
本站(newscan.com.tw)以 PHP 建置、不使用 CGI;上述原則來自替客戶盤點舊網站的實務,不涉及特定客戶資料。
八、結論
CGI 是動態網頁的起點,用最簡單的方式定義了「伺服器怎麼呼叫程式」,也因為太簡單而被常駐式的架構取代。理解它,就理解了 PHP-FPM、WSGI、Tomcat 這些現代方案在解決什麼問題;至於實際開發,請選擇主流的伺服器端語言與框架,比較見〈網頁程式設計是什麼〉。
九、常見問答 FAQ
CGI 是什麼?
CGI 和 PHP 有什麼不同?
CGI 現在還有人用嗎?
cgi-bin 是什麼目錄?
CGI 為什麼會被淘汰?
參考來源
- IETF,〈RFC 3875: The Common Gateway Interface (CGI) Version 1.1〉,IETF,2004。
- Apache Software Foundation,〈Apache Tutorial: Dynamic Content with CGI〉,Apache HTTP Server 官方文件。
- Python Software Foundation,〈What's New In Python 3.13:Removed Modules〉,Python 官方文件。
- PHP Group,〈FastCGI Process Manager (FPM)〉,PHP 官方文件。
- 新視野網頁設計,〈Perl 是什麼?語法介紹、正則表達式與現況〉,本站自有內容。
各伺服器與語言對 CGI 的支援狀態依撰寫時查閱的官方文件整理;第七節為本站盤點舊網站時的實務原則,不涉及特定客戶資料。