BLOG
網站專欄 Q & A
網站技術

CGI 是什麼?運作原理、Perl 與 Python 範例、現況與替代方案

CGI 是網頁伺服器與外部程式之間最早的溝通規範:訪客送出表單,伺服器啟動一支程式處理,程式把結果印成 HTML 回傳。1990 年代所有「會動」的網頁都靠它,今天它幾乎完全被 FastCGI、PHP-FPM 與各語言的應用伺服器取代。這篇文章說明 CGI 是什麼、怎麼運作、用 Perl 與 Python 各寫一支範例,然後回答兩個實務問題:為什麼它被淘汰、舊主機的 cgi-bin 該怎麼處理。本文屬於《網頁程式語言》系列,總覽見〈網頁程式設計是什麼〉。

CGI(Common Gateway Interface)示意圖:網頁伺服器把請求交給外部程式處理再回傳 HTML

一、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_METHODQUERY_STRINGREMOTE_ADDR 等),POST 的內容則從標準輸入送給程式。
  • 程式處理並輸出:程式讀取資料、做運算或查資料庫,先印出至少一行 HTTP 標頭(Content-Type: text/html)、一個空行,再印出 HTML。
  • 程序結束,伺服器回傳:伺服器把程式的標準輸出原樣送給瀏覽器,然後這支程序就結束了。下一個請求再從頭啟動一支。

「每個請求啟動一支新程序」正是 CGI 最大的優點也是致命缺點:簡單、語言無關,但流量一大,光是不斷啟動程序就會拖垮伺服器。這一層架構在網頁伺服器應用程式伺服器的分工中就能看出演進的方向。

三、CGI 程式範例:Perl

Perl 是 CGI 時代的主流語言,以下範例顯示一張表單並回應輸入的姓名。Perl 語言本身的語法見〈Perl 是什麼〉。

Perl(cgi-bin/form.cgi)
#!/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 自行解析。

Python(cgi-bin/form.py)
#!/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(Common Gateway Interface,通用閘道介面)是一套規範,定義網頁伺服器如何把 HTTP 請求交給外部程式處理、再把程式輸出當成回應送回瀏覽器。它不是程式語言,Perl、Python、C、shell 都能寫 CGI 程式,慣例放在網站的 cgi-bin 目錄。CGI 於 1993 年提出、2004 年以 RFC 3875 文件化,是動態網頁的起點;因為每個請求都要啟動一支新程序、效能差,今天已被 FastCGI、PHP-FPM 與各語言的應用伺服器取代。
CGI 和 PHP 有什麼不同?
CGI 是伺服器呼叫外部程式的規範,PHP 是程式語言,兩者層次不同。早期 PHP 也能以 CGI 方式執行,但 PHP 之所以在 2000 年代取代 Perl CGI,正是因為它改以伺服器模組(mod_php)或常駐程序(PHP-FPM)運作,不必為每個請求付啟動程序的成本,效能好得多,而且直接嵌在 HTML 裡寫、部署簡單。今天說「PHP 網站」幾乎都是 PHP-FPM 架構,和傳統 CGI 已無關係。
CGI 現在還有人用嗎?
新網站幾乎不再用傳統 CGI,但它沒有完全消失:Apache 等伺服器仍支援 mod_cgi,許多老主機的 cgi-bin 裡還留著 Perl 程式,部分嵌入式裝置與網路設備的管理介面也還用 CGI。取而代之的是常駐式架構:PHP 用 PHP-FPM(FastCGI),Python 用 WSGI 或 ASGI 伺服器,Java 用 Tomcat,.NET 用 Kestrel,Node.js 自己就是伺服器。Python 甚至在 3.13 版移除了內建的 cgi 模組,可見官方也視它為過時技術。
cgi-bin 是什麼目錄?
cgi-bin 是網頁伺服器上專門放 CGI 程式的目錄,伺服器會把對這個目錄的請求當成「執行程式」而不是「送出檔案」。早期網站的留言板、訪客計數器、表單寄信程式都放在這裡,副檔名常是 .cgi 或 .pl。接手舊網站時看到 cgi-bin,建議先查存取日誌確認是否還有人使用:沒有就下線並對舊網址做轉址;仍在用的功能用現有系統重做,不要搬遷,因為新主機多半沒有 CGI 環境,而且二十年前的程式普遍缺乏輸入驗證,是常見的資安破口。
CGI 為什麼會被淘汰?
只有一個原因:效能。CGI 規定每一個請求都要啟動一支新程序、執行完就結束,直譯器啟動、載入模組、連資料庫的成本每次重付,流量一大伺服器就被拖垮。解法沿著「讓程式常駐」演進:先是把直譯器嵌進伺服器(mod_perl、mod_php),再是 FastCGI 讓程式常駐並透過 socket 接收請求(PHP-FPM),最後是各語言自帶應用伺服器、前面用 Nginx 反向代理。CGI 的概念沒有錯,它只是把 HTTP 請求與回應攤在眼前的最簡單做法,教學上仍有價值。

參考來源

  1. IETF,〈RFC 3875: The Common Gateway Interface (CGI) Version 1.1〉,IETF,2004。
  2. Apache Software Foundation,〈Apache Tutorial: Dynamic Content with CGI〉,Apache HTTP Server 官方文件。
  3. Python Software Foundation,〈What's New In Python 3.13:Removed Modules〉,Python 官方文件。
  4. PHP Group,〈FastCGI Process Manager (FPM)〉,PHP 官方文件。
  5. 新視野網頁設計,〈Perl 是什麼?語法介紹、正則表達式與現況〉,本站自有內容。

各伺服器與語言對 CGI 的支援狀態依撰寫時查閱的官方文件整理;第七節為本站盤點舊網站時的實務原則,不涉及特定客戶資料。

關於作者

內容揭露:本文由新視野網頁設計 SEO 團隊撰寫。文中連結的站內指南與延伸閱讀均為本站自有內容;新視野提供網頁設計與 SEO/AI SEO 服務,讀者在採用本文建議前請自行評估是否符合自身情況。文中引用的第三方研究與官方文件皆附可點擊出處,歡迎查證。

新視野網頁設計 SEO 團隊

新視野網頁設計自 2005 年起投入企業網站建置與搜尋行銷,服務範圍涵蓋 RWD 網站設計、技術 SEO、結構化資料佈署,以及 AI 搜尋時代的 AEO/GEO 內容優化。本文由新視野 SEO 團隊撰寫、審閱並持續維護更新。

服務據點:
台中(總公司)台中市南區忠明南路 758 號 21 樓 B4台北高雄
聯絡電話:
04-2260-1329
公司資訊:
關於我們公司位置線上詢價
對外平台:
FacebookLinkedIn
本站同主題內容:
Perl 是什麼PHP 是什麼網頁伺服器是什麼網頁程式設計是什麼

歡迎推廣本文,請務必連結(LINK)本文出處:新視野網頁設計公司