Apache HTTP Server 版本2.2
服務(wù)器端包含提供了一種對現(xiàn)有HTML文檔增加動態(tài)內(nèi)容的方法。
相關(guān)模塊 | 相關(guān)指令 |
---|---|
本文針對服務(wù)器端包含(SSI)討論如何配置服務(wù)器以允許SSI ,并介紹一些對現(xiàn)有HTML頁面增加動態(tài)內(nèi)容的基本SSI技術(shù)。
本文后部將討論用SSI做一些稍微高級的事情,比如SSI指令中的條件語句。
SSI是嵌入HTML頁面中的指令,在頁面被提供時由服務(wù)器進(jìn)行運算,以對現(xiàn)有HTML頁面增加動態(tài)生成的內(nèi)容,而無須通過CGI程序提供其整個頁面,或者使用其他動態(tài)技術(shù)。
至于什么時候應(yīng)當(dāng)用SSI ,而什么時候應(yīng)當(dāng)用某些程序生成整個頁面,取決于頁面中有多少內(nèi)容是靜態(tài)的,又有多少內(nèi)容需要在每次頁面被提供時重新計算。SSI是一種增加小段動態(tài)信息的好方法,比如當(dāng)前時間。如果你的頁面大部分內(nèi)容是在被提供時動態(tài)生成的,那就要另找方案了。
要使服務(wù)器允許SSI ,必須在httpd.conf
或.htaccess
文件中有如下配置:
Options +Includes
這樣就告訴服務(wù)器允許解析文件中的SSI指令。注意,在多數(shù)配置中,多個Options
指令會互相覆蓋,所以可能需要對使用SSI的目錄專門使用一個Options
指令,以確保其有效。
并非所有文件中的SSI指令都會被解析,必須告訴Apache應(yīng)該解析哪些文件。有兩種方法使Apache解析帶有特定后綴名的文件,比如:.shtml
,配置如下:
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
該方法的缺點之一是,為了使文件具有.shtml
后綴從而執(zhí)行其中的指令,需要加入SSI指令的現(xiàn)有文件的名字,以及所有指向此頁面的連接。
另一種方法是,使用XBitHack
指令:
XBitHack on
XBitHack
告訴Apache解析所有設(shè)置了執(zhí)行位的文件中的SSI指令。這樣,無需修改文件名,只要用chmod
使文件變成可執(zhí)行的,就可以對現(xiàn)有頁面增加SSI指令。
chmod +x pagename.html
這里簡要說明一點:偶然會有人向你推薦,無須用帶.shtml
的文件名,只要使Apache解析所有.html
文件的SSI就可以了。那些人可能沒聽說過XBitHack
。要知道,這樣做會使Apache在發(fā)送文件到客戶端之前通讀此文件,即使其中并沒有任何SSI指令,從而對速度有很不利的影響,所以這并不是好辦法。
當(dāng)然,在Windows上,沒有對應(yīng)的執(zhí)行位可以設(shè)置,所以對你的配置方法就有一些限制。
在默認(rèn)配置的情況下,Apache不會為SSI頁面發(fā)送最后修改日期或者內(nèi)容長度的HTTP頭,因為這些值對動態(tài)頁面來說難以確定。這樣會阻止頁面被緩沖,導(dǎo)致客戶端性能有明顯的下降。有兩種解決方法:
XBitHack Full
,告訴Apache在判斷最后修改日期時,只查看被請求文件本身的日期,而忽略其中包含的其它文件的修改日期。mod_expires
提供的指令為文件設(shè)置一個明確的過期時間,并告訴瀏覽器和代理這個文件可以被緩沖。SSI指令有如下語法:
<!--#element attribute=value attribute=value ... -->
類似于HTML注釋,即使沒有正確配置SSI ,它也不會被瀏覽器顯示,但在HTML代碼中可見。而若正確配置了SSI ,則指令會被其結(jié)果所取代。
其中的元素可以有許多,我們會在下一個版本的文檔中討論其中的大多數(shù),而在這里,僅舉幾個SSI的例子。
<!--#echo var="DATE_LOCAL" -->
echo
元素用于顯示一個變量的值。標(biāo)準(zhǔn)變量有很多,其中包含對CGI程序有效的所有環(huán)境變量。并且還可以用set
元素定義你自己的專用變量。
如果你不喜歡這種日期格式,可以用config
元素的timefmt
屬性,改變其格式。
<!--#config timefmt="%A %B %d, %Y" -->
Today is <!--#echo var="DATE_LOCAL" -->
This document last modified <!--#flastmod file="index.html" -->
這個元素使用timefmt
的格式配置。
這也是SSI很常見的一個用途:包含一個CGI程序的輸出,比如人人喜歡的"點擊計數(shù)器"。
<!--#include virtual="/cgi-bin/counter.pl" -->
以下是一些在HTML中使用SSI的特殊例子。
前面我們提到過可以用SSI告訴用戶文檔是什么時候被修改的,但是具體實現(xiàn)方法卻未說明。將以下代碼放到HTML中,會在頁面中產(chǎn)生一個時間戳,當(dāng)然,你必須首先按前面的方法啟用SSI 。
<!--#config timefmt="%A %B %d, %Y" -->
This file last modified <!--#flastmod file="ssi.shtml" -->
不用說,你應(yīng)該用你實際引用的文件名來替換ssi.shtml
,所以,如果你想簡單地在所有文件中使用這段通用代碼以達(dá)到這個目的,這個方法就并不方便,就需要用到LAST_MODIFIED
變量:
<!--#config timefmt="%D" -->
This file last modified <!--#echo var="LAST_MODIFIED" -->
有關(guān)timefmt
格式的細(xì)節(jié),可以到google查找strftime
,其語法是相同的。
當(dāng)你管理一個擁有許多頁面的站點,你會發(fā)現(xiàn)對所有頁面同時做改動是很痛苦的,尤其是在試圖對所有頁面維持某種標(biāo)準(zhǔn)視覺效果的時候。
使用包含一個頁眉/頁腳的方法,可以減輕修改的負(fù)擔(dān)。你只要制作一個頁腳文件,并用include
命令包含到每個頁面即可。include
元素能按file
屬性或virtual
屬性判斷應(yīng)該包含的文件。file
屬性是一個相對于當(dāng)前目錄的文件路徑,即不能是一個絕對路徑(以"/"開頭)或包含"../"的路徑。virtual
屬性可能更有用,它是一個相對于被提供的文檔的URL ,可以以"/"開頭,但必須與被提供的文檔位于同一服務(wù)器上。
<!--#include virtual="/footer.html" -->
SSI指令和頁腳文件相結(jié)合使用是很有用的,比如在頁腳文件中使用LAST_MODIFIED
指令。SSI指令可以出現(xiàn)在包含文件中,而include
可以嵌套,即一個包含文件還可以再包含另外一個。
config
除了能設(shè)置時間格式,還有兩種用途。
當(dāng)SSI指令發(fā)生錯誤時,會產(chǎn)生如下消息:
[an error occurred while processing this directive]
為了改變消息的形式,可以使用config
元素的errmsg
屬性:
<!--#config errmsg="[It appears that you don't know how to use SSI]" -->
希望最終用戶永遠(yuǎn)也不會看到這個消息,因為在網(wǎng)站投入運行之前你已經(jīng)把這些問題都解決了。是嗎?
還可以使用config
的sizefmt
屬性設(shè)置返回的文件大小的格式,或者是以bytes
為單位,或者是以Kb或Mb為單位的簡寫(abbrev)
。
我期望未來幾個月內(nèi)能再寫一篇小型的CGI程序使用SSI的文章,而這里僅介紹exec
的使用。SSI確實可以利用shell(/bin/sh
,精確地說,還可以是Win32中的DOS shell)來執(zhí)行命令。下例產(chǎn)生一個目錄列表:
<pre>
<!--#exec cmd="ls" -->
</pre>
或者在Windows中:
<pre>
<!--#exec cmd="dir" -->
</pre>
你可能會發(fā)現(xiàn),在Windows中這個指令的結(jié)果有些奇怪,dir
的輸出中包含有字符串"<dir
>",它會使瀏覽器產(chǎn)生混淆。
注意,這個功能是極度危險的,因為它會執(zhí)行任何包含在exec
標(biāo)記中的命令。如果用戶有可能修改你的網(wǎng)頁內(nèi)容,比如"留言本",那么你一定要關(guān)閉這個功能?梢栽Options
指令中加上IncludesNOEXEC
參數(shù),以關(guān)閉exec
功能,同時又保留SSI。
除了分離內(nèi)容,Apache SSI還有設(shè)置變量的操作,并且還可以將這些變量用在比較和條件表達(dá)式中。
本文中討論的大多數(shù)功能僅在Apache1.2及更新版本中有效。如果你運行的不是Apache1.2及更新版本,請立刻或者盡快升級,現(xiàn)在就動手,我們會等你弄好了再繼續(xù)往下講。
使用set
指令可以設(shè)置變量以備后用,其語法是:
<!--#set var="name" value="Rich" -->
除了設(shè)置字面變量以外,還可以設(shè)置其他任何變量,比如環(huán)境變量和此前提到過的一些變量(如LAST_MODIFIED
),作為你的專用變量。在變量名前面綴以"$",表示它是一個變量,而不是一個字面字符串。
<!--#set var="modified" value="$LAST_MODIFIED" -->
若要在字面字符串中使用"$",必須使用轉(zhuǎn)義符號"\$":
<!--#set var="cost" value="\$100" -->
最后,如果要在較長的字符串中使用變量,可以用花括號把變量名括起來,以免變量名與其他字符混淆(要對這種情況舉例說明有點難度,但還是希望你能領(lǐng)會)。
<!--#set var="date" value="${DATE_LOCAL}_${DATE_GMT}" -->
有了變量,就可以設(shè)置和比較它們的值以表示條件,SSI也因此成為一種簡潔的編程語言。mod_include
提供了if
, elif
, else
, endif
等結(jié)構(gòu)以構(gòu)造條件語句,從同一個頁面高效地產(chǎn)生多個邏輯頁面。
條件結(jié)構(gòu)如下:
<!--#if expr="test_condition" -->
<!--#elif expr="test_condition" -->
<!--#else -->
<!--#endif -->
test_condition可以是任何邏輯比較:可以是一個值和另一個值比較,也可以是測試一個特定的值是否為"真"(一個給定的字符串如果非空則為真)。完整的比較操作符列表,參見mod_include
。以下是可能會用到的一些例子。
在配置文件中,可以這樣設(shè)置:
BrowserMatchNoCase macintosh Mac
BrowserMatchNoCase MSIE InternetExplorer
如果客戶端在Macintosh上運行Internet Explorer,則上例設(shè)置環(huán)境變量"Mac"和"InternetExplorer"都為真。
然后,在允許SSI的文檔中,可以這樣設(shè)置:
<!--#if expr="${Mac} && ${InternetExplorer}" -->
Apologetic text goes here
<!--#else -->
Cool JavaScript code goes here
<!--#endif -->
我一點也不反對在Mac上運行IE,只是上個星期我花了好幾個小時試圖在Mac上的IE中使用JavaScript,而它在其他地方都能正常運作,以上只是一個臨時的妥協(xié)方案。
任何其他變量(或者是你定義的,或者是標(biāo)準(zhǔn)的環(huán)境變量)都可以用于條件語句。利用Apache的SetEnvIf
以及其他相關(guān)指令設(shè)置環(huán)境變量,此功能可以很好地實現(xiàn)動態(tài)頁面而無須借助于CGI。
SSI固然不能替代CGI或者其他動態(tài)頁面技術(shù),但它是在頁面中插入眾多小型的動態(tài)片段的優(yōu)秀方法,而無須大量額外的操作。