Apache HTTP Server 版本2.2
相關(guān)模塊 | 相關(guān)指令 |
---|---|
CGI(公共網(wǎng)關(guān)接口)定義了web服務(wù)器與外部內(nèi)容生成程序之間交互的方法,通常是指CGI程序或者CGI腳本,它是在網(wǎng)站上實現(xiàn)動態(tài)頁面的最簡單和常用的方法。本文將對如何在Apache web服務(wù)器上建立CGI以及如何編寫CGI程序進(jìn)行介紹。
要讓CGI程序能正常運作,必須配置Apache以允許CGI的執(zhí)行,其方法有多種。
ScriptAlias
指令使Apache允許執(zhí)行一個特定目錄中的CGI程序。當(dāng)客戶端請求此特定目錄中的資源時,Apache假定其中所有的文件都是CGI程序并試圖運行它。
ScriptAlias
指令形如:
ScriptAlias /cgi-bin/ /usr/local/apache2/cgi-bin/
如果Apache被安裝到默認(rèn)位置,默認(rèn)的配置文件httpd.conf
中就會有上述配置。ScriptAlias
與Alias
指令非常相似,都是定義了映射到一個特定目錄的URL前綴,兩者一般都用于指定位于DocumentRoot
以外的目錄,其不同之處是ScriptAlias
又多了一層含義,即URL前綴后面的任何文件都被視為CGI程序。所以,上述例子會指示Apache:任何以/cgi-bin/
開頭的資源都將映射到/usr/local/apache2/cgi-bin/
目錄中,且視之為CGI程序。
例如,如果有URL為http://www.example.com/cgi-bin/test.pl
的請求,Apache會試圖執(zhí)行/usr/local/apache2/cgi-bin/test.pl
文件并返回其輸出。當(dāng)然,這個文件必須存在而且可執(zhí)行,并以特定的方法產(chǎn)生輸出,否則Apache返回一個出錯消息。
由于安全原因,CGI程序通常被限制在ScriptAlias
指定的目錄中,這樣,管理員就可以嚴(yán)格控制誰可以使用CGI程序。但是,如果采取了恰當(dāng)?shù)陌踩胧,則沒有理由不允許其他目錄中的CGI程序運行。比如,你可能希望用戶在UserDir
指定的宿主目錄中存放頁面,而他們有自己的CGI程序,但無權(quán)訪問cgi-bin
目錄,這樣,就產(chǎn)生了運行其他目錄中CGI程序的需求。
允許CGI在任意目錄執(zhí)行需要兩個步驟:第一步,必須用AddHandler
或SetHandler
指令激活cgi-script
處理器。第二步,必須在Options
指令中啟用ExecCGI
選項。
可以在主配置文件中,使用Options
指令顯式地允許特定目錄中CGI的執(zhí)行:
<Directory /usr/local/apache2/htdocs/somedir>
Options +ExecCGI
</Directory>
上述指令使Apache允許CGI文件的執(zhí)行。另外,還必須告訴服務(wù)器哪些文件是CGI文件。下面的AddHandler
指令告訴服務(wù)器所有帶有cgi
或pl
后綴的文件是CGI程序:
AddHandler cgi-script .cgi .pl
.htaccess
指南示范了怎樣在沒有權(quán)限修改httpd.conf
文件的情況下激活CGI程序。
為了允許用戶目錄中所有以".cgi
"結(jié)尾的文件作為CGI程序執(zhí)行,你可以使用以下配置:
<Directory /home/*/public_html>
Options +ExecCGI
AddHandler cgi-script .cgi
</Directory>
如果你想在用戶目錄中指定一個cgi-bin
子目錄,其中所有的文件都被當(dāng)作CGI程序,你可以這樣配置:
<Directory /home/*/public_html/cgi-bin>
Options ExecCGI
SetHandler cgi-script
</Directory>
編寫CGI程序和"常規(guī)"程序之間有兩個主要的不同。
首先,在CGI程序的所有輸出前面必須有一個HTTP的MIME類型的頭,對客戶端指明所接收內(nèi)容的類型,大多數(shù)情況下,像這樣:
Content-type: text/html
其次,輸出要求是HTML形式的,或者是瀏覽器可以顯示的其他某種形式。多數(shù)情況下,輸出是HTML形式的,但偶然也會輸出一個gif圖片或者其他非HTML的內(nèi)容。
除了這兩點,編寫CGI程序和編寫其他程序大致相同。
這個CGI程序的例子在瀏覽器中打印一行文字。把下列存為first.pl
文件,并放在你的cgi-bin
目錄中。
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "Hello, World.";
即使不熟悉Perl語言,你也應(yīng)該能看出它干了什么。第一行,告訴Apache這個文件可以用/usr/bin/perl
(或者任何你正在使用的shell)解釋并執(zhí)行。第二行,打印上述要求的內(nèi)容類型說明,并帶有兩個換行,在頭后面留出空行,以示HTTP頭的結(jié)束。第三行,打印文字"Hello, World."。程序到此結(jié)束。
打開你喜歡的瀏覽器并輸入地址:
http://www.example.com/cgi-bin/first.pl
或者是你存放程序的其他位置,就可以在瀏覽器窗口中看到一行:Hello, World.
。雖然并不怎么激動人心,但是一旦這個程序能正常運行,那么就可能運行其他任何程序。
使用瀏覽器從網(wǎng)絡(luò)訪問CGI程序,可能會發(fā)生四種情況:
Content-Type
。記住,服務(wù)器不是以你的用戶身份運行的,在服務(wù)器啟動后,擁有的是一個非特權(quán)用戶的權(quán)限(通常是nobody
或www
)而需要更大的權(quán)限以允許文件的執(zhí)行。通常,給予nobody
足夠的權(quán)限以執(zhí)行文件的方法是,對文件賦予任何人皆可執(zhí)行的權(quán)限:
chmod a+x first.pl
另外,如果需要對其他文件進(jìn)行讀取或?qū)懭,也必須對這些文件賦予正確的權(quán)限。
當(dāng)你在命令行執(zhí)行一個程序,某些信息會自動傳給shell而無須你操心,比如PATH
,告訴shell你所引用的文件可以在哪兒找到。
但是,在CGI程序通過web服務(wù)器執(zhí)行時,則沒有此PATH
,所以,你在CGI程序中引用的任何程序(如sendmail
)都必須指定其完整的路徑,使shell能找到它們以執(zhí)行你的CGI程序。
一種普通的用法是,在CGI程序的第一行中指明解釋器(通常是perl
),形如:
#!/usr/bin/perl
必須保證它的確指向解釋器。
另外,如果CGI程序依賴于某些環(huán)境變量,你要確保所需要的變量已經(jīng)正確的由Apache進(jìn)行了傳遞。
多數(shù)CGI程序失敗的原因在于程序本身有問題,尤其是在已經(jīng)消除上述兩種錯誤而CGI掛起的情況下。在用瀏覽器測試以前,先在命令行中執(zhí)行你的程序,能夠發(fā)現(xiàn)大多數(shù)的問題。比如:
cd /usr/local/apache2/cgi-bin
./first.pl
(不要調(diào)用perl
解釋程序,因為shell和Apache會根據(jù)腳本第一行的路徑信息找到解釋器)
你最先看到的輸出內(nèi)容應(yīng)當(dāng)是一組HTTP頭,包括Content-Type
和結(jié)尾的空行。如果你看到了別的什么東西,那么當(dāng)你在服務(wù)器上試運行時,Apache會返回 Premature end of script headers
錯誤。參見上面的編寫CGI程序以獲得更多信息。
錯誤日志是你的朋友。任何錯誤都會在錯誤日志中有所記載,所以你應(yīng)該首先查看它。如果你的網(wǎng)站空間提供者不允許訪問錯誤日志,那么你應(yīng)該考慮換一個空間提供者。學(xué)會閱讀錯誤日志,可以快速找出問題并快速解決。
suexec允許CGI程序根據(jù)其所在虛擬主機或用戶宿主目錄的不同而以不同的用戶權(quán)限運行。suexec有極其嚴(yán)格的權(quán)限校驗,任何校驗失敗都會使CGI程序遭遇 Premature end of script headers
錯誤。
為了檢查你是否使用了suexec ,運行 apachectl -V
并檢查SUEXEC_BIN
的位置。如果Apache在啟動時發(fā)現(xiàn)suexec
二進(jìn)制文件正存在于此,那么suexec將會被激活。
除非你很精通suexec,否則請不要使用它。要禁用它,只要刪除(或重命名)SUEXEC_BIN
所指定位置的suexec
二進(jìn)制文件并重啟服務(wù)器就可以了。如果你又想啟用它,請首先閱讀suexec文檔以詳細(xì)了解其運行機制,然后運行 suexec -V
命令找到suexec日志文件,并使用該日志文件找到你違反了哪條判斷規(guī)則。
當(dāng)你的CGI編程逐漸深入,理解幕后的操作(尤其是瀏覽器和服務(wù)器之間是如何通訊的)就變得很有用了。因為雖然成功地寫了一個程序打印"Hello, World",但并沒有實際的用處。
環(huán)境變量是使用計算機時到處都會用到的變量,比如路徑(對實際文件的一個搜索路徑以補全你的輸入)、你的用戶名以及你的終端類型等等。在命令行輸入 env
,可以得到當(dāng)天標(biāo)準(zhǔn)的環(huán)境變量列表。
在CGI處理過程中,服務(wù)器和瀏覽器都會設(shè)置環(huán)境變量,比如瀏覽器類型(Netscape、IE、Lynx)、服務(wù)器類型(Apache、IIS、WebSite)以及將要執(zhí)行的CGI程序名稱等等。
所有這些變量對CGI程序員都有效,但只是客戶端-服務(wù)器通訊的一半內(nèi)容。完整的變量列表參見http://hoohoo.ncsa.uiuc.edu/cgi/env.html
這個簡單的CGI程序列出了所有的環(huán)境變量,Apache發(fā)行版的cgi-bin
目錄中還有一個類似的程序。注意,有些變量是必須的,有些則是可選的,所以你可能會看見一些官方列表中沒有的變量。另外,Apache有多種方法可以在默認(rèn)提供的變量之外增加你的專用環(huán)境變量。
#!/usr/bin/perl
print "Content-type: text/html\n\n";
foreach $key (keys %ENV) {
print "$key --> $ENV{$key}<br>";
}
服務(wù)器和客戶端之間的其他通訊都通過標(biāo)準(zhǔn)輸入設(shè)備(STDIN
)和標(biāo)準(zhǔn)輸出設(shè)備(STDOUT
)完成。通常,STDIN
是指鍵盤或者一個程序所作用的一個文件,STDOUT
指控制臺或顯示器。
當(dāng)你POST
一個網(wǎng)絡(luò)表格到一個CGI程序時,表格中的數(shù)據(jù)被捆扎為一個特殊形式通過STDIN
傳送給CGI程序,這樣,這個程序就可以處理這些數(shù)據(jù),仿佛這些數(shù)據(jù)是來自鍵盤或者一個文件。
這種"特殊形式"很簡單,一個字段名稱及其值,中間用等號(=)連接,多個這樣的字段對用與符號(&)連接。非常規(guī)字符,如空格、"&"號和"="號,被轉(zhuǎn)換為其等值的十六進(jìn)制以免出問題。整個字符串形如:
name=Rich%20Bowen&city=Lexington&state=KY&sidekick=Squirrel%20Monkey
有時,你會發(fā)現(xiàn)URL后面也會帶有這樣的字符串。這種形式會使服務(wù)器以這個字符串的內(nèi)容設(shè)置環(huán)境變量QUERY_STRING
,稱為GET
請求。你的HTML表格在FORM
標(biāo)簽中設(shè)置METHOD
屬性,以指定傳送數(shù)據(jù)的動作使用GET
或POST
。
你的程序必須把這個字符串分解以獲得有用信息。所幸,有庫和模塊可以幫助你處理這些數(shù)據(jù),還有為你的CGI程序達(dá)成其他目的的處理器。
編寫CGI程序時,你應(yīng)該考慮使用代碼庫或模塊來完成大多數(shù)瑣碎的工作,以減少錯誤并更快地開發(fā)。
如果用Perl語言編寫CGI程序,可用的模塊見CPAN ,最常用的模塊是CGI.pm
。也可以考慮用CGI::Lite
,它實現(xiàn)了一個在多數(shù)程序中所有必須的最小功能集。
如果用C語言編寫CGI程序,則有很多選擇,其中之一是CGIC
庫,來自http://www.boutell.com/cgic/
網(wǎng)上有大量的CGI資源?梢栽赨senet組comp.infosystems.www.authoring.cgi和別人討論CGI相關(guān)問題。HTML Writers Guild 的郵件列表是一個優(yōu)秀的問題解答資源。更多資源在http://www.hwg.org/lists/hwg-servers/
另外,還可以閱讀CGI規(guī)范,其中有CGI程序操作的所有細(xì)節(jié),原始版本見NCSA ,另有一個更新草案見Common Gateway Interface RFC project
當(dāng)你向一個郵件列表或者新聞組提交CGI相關(guān)問題時,你應(yīng)該確保提供了足夠的信息以更容易地發(fā)現(xiàn)并解決問題,諸如:發(fā)生了什么事、你希望得到什么結(jié)果、結(jié)果與你所期望的有什么出入、你運行的服務(wù)器、CGI程序是用什么語言編寫的、如果可能就提供那個討厭的代碼。
注意,不要把CGI相關(guān)問題提交到Apache bug數(shù)據(jù)庫,除非你堅信發(fā)現(xiàn)的是Apache源代碼中的問題。