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