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