Apache HTTP 伺服器 2.4 版本
相關模組 | 相關指令 |
---|---|
這篇文章處理伺服器端包含,通常簡稱 SSI。在這篇文章中,我將談論如何設定你的伺服器允許 SSI,並且介紹一些基本的 SSI 技巧,以將動態內容加入你現有的 HTML 頁面中。
在文章的後段,我們將討論一些比較進階,且可以藉由 SSI 達成的功能,例如在 SSI 指令中加入條件陳述式。
SSI (伺服器端包含) 是放在 HTML 頁面中的指令,並在頁面送出的同時在伺服器上評估。它可以讓你將動態產生的內容加入現有的 HTML 頁面,而無需透過 CGI 程式或其他動態技術來提供整個頁面。
例如,你可以在現有的 HTML 頁面中放置一個指令,例如
<!--#echo var="DATE_LOCAL" -->
然後,當頁面送出時,這個片段將會被評估,並以它的值替換
Tuesday, 15-Jan-2013 19:28:54 EST
選擇何時使用 SSI 以及何時完全透過某些程式產生網頁,通常取決於網頁中有多少內容是靜態的,以及多少內容每次送出網頁時需要重新計算。SSI 是新增小段資訊的絕佳方式,例如顯示在上面的目前時間。但是如果網頁大部分的內容在送出時才產生,則需要尋找其他解決辦法。
要在伺服器上允許 SSI,您必須在 httpd.conf
檔案或 .htaccess
檔案中,擁有下列指令
Options +Includes
它告訴 Apache 您想要允許對檔案進行 SSI 指令解析。請注意,大多數設定都包含多個 Options
指令,可以用來覆寫彼此。您可能需要將 Options
套用在您希望啟用 SSI 的特定目錄中,以確保它會最後評估。
並非任何檔案都會進行 SSI 指令的解析。您必須告訴 Apache 哪些檔案應該進行解析。有兩個方法可以做到這一點。您可以告訴 Apache 解析任何具有特定檔案副檔名的檔案,例如 .shtml
,使用下列指令
AddType text/html .shtml AddOutputFilter INCLUDES .shtml
此方法的一個缺點是,如果您想要將 SSI 指令新增到現有網頁,則必須變更該網頁的名稱,並變更所有連結到該網頁的連結,才能給予它 .shtml
副檔名,才能執行那些指令。
另一個方法是使用 XBitHack
指令
XBitHack on
XBitHack
會告訴 Apache 如果檔案設定了執行位元,就解析該檔案的 SSI 指令。因此,要將 SSI 指令新增到現有網頁,不需要變更檔案名稱,只需要使用 chmod
命令使檔案可以執行即可。
chmod +x pagename.html
簡短說明一下不建議做的事情。您偶爾會看到有人建議,直接告訴 Apache 解析所有 .html
檔案的 SSI,這樣就不必處理 .shtml
檔案名稱。這些人可能不知道 XBitHack
。請記住,這樣做會讓 Apache 讀取傳送給客戶端的每個檔案,即使它們不包含任何 SSI 指令。這會讓速度慢很多,並不是個好主意。
當然,在 Windows 中沒有所謂的執行位元設定,這會稍微限制您的選項。
在預設設定中,Apache 不會在 SSI 網頁上傳送上次修改日期或內容長度 HTTP 標頭,因為這些值對於動態內容來說很難計算。這可能會讓您的文件無法快取,並導致客戶端效能顯著降低。有兩個方法可以解決這個問題
XBitHack Full
組態。這會指示 Apache 只查看原來要求的檔案日期來判斷上次修改日期,而忽略任何包含檔案的修改日期。mod_expires
提供的指令,在檔案上設定明確的過期時間,這樣可以讓瀏覽器和代理伺服器知道暫存這些檔案是可以接受的。SSI 指令有下列語法
<!--#function attribute=value attribute=value ... -->
其格式就像 HTML 註解,因此如果你沒有正確啟用 SSI,瀏覽器會忽略該指令,但它仍然會顯示在 HTML 原始碼中。如果你正確地設定了 SSI 組態,指令會以其結果取代。
function 可以是許多項目的其中之一,而在本系列的下一篇文章中,我們會進一步探討大部分的項目。以下是你可以使用 SSI 執行的部分範例,供你參考
<!--#echo var="DATE_LOCAL" -->
echo
函數僅會輸出變數的值。有許多標準變數,其中包括一整組可供 CGI 程式使用的環境變數。此外,你可以使用 set
函數定義自己的變數。
如果你不喜歡日期的列印格式,你可以使用 config
函數,並透過 timefmt
屬性來修改該格式。
<!--#config timefmt="%A %B %d, %Y" -->
今天是 <!--#echo var="DATE_LOCAL" -->
此文件最近修改於 <!--#flastmod file="index.html" -->
這個函數也可依 timefmt
格式組態設定。
這是 SSI 相當常見的用途 - 輸出 CGI 程式的結果,例如每個人最喜歡的「點閱次數計數器」。
<!--#include virtual="/cgi-bin/counter.pl" -->
以下是使用 SSI 在 HTML 文件中執行的部分範例。
稍早我們提到你可以使用 SSI 告知使用者文件最近修改的時間。然而,實際執行的方法有點疑問。將下列程式碼置於你的 HTML 文件中,即可在你的頁面上加上時間戳。當然,你必須正確啟用 SSI,如上所述。
<!--#config timefmt="%A %B %d, %Y" -->
檔案最後修改時間 <!--#flastmod file="ssi.shtml" -->
當然,你必須將 ssi.shtml
替換為你實際要引用的檔案名稱。如果你只是想找一段可用於貼上到任何檔案的通用程式碼,這麼做比較不方便,因此你可能想改用 LAST_MODIFIED
變數
<!--#config timefmt="%D" -->
此檔案最後修改於<!--#echo var="LAST_MODIFIED" -->
關於timefmt
格式的更多詳細資料,請前往您最喜歡的搜尋網站並搜尋strftime
。語法相同。
如果您管理的多個頁面組成一個網站,您可能會發現對這些頁面進行變更可能是一種苦差事,尤其是當您試著在所有這些頁面維持某種標準樣式時。
使用包含檔作為標頭和/或頁腳可以減輕這些更新的負擔。您只需要建立一個頁腳檔,然後將它與每個頁面包含於include
SSI 命令中。include
函數可以用file
屬性或virtual
屬性來決定要包含的文件。file
屬性是檔案路徑,從目前的目錄開始。這表示它不能是絕對路徑(由「/」開頭),也不能將「../」包含於路徑中。virtual
屬性可能是更有用的,並且應指定相對於正在顯示的文件的網址。它可以用「/」開頭,但必須和正在顯示的文件位於同一個伺服器上。
<!--#include virtual="/footer.html" -->
我經常會合併最後二個項目,在要包含的頁腳檔中置入 LAST_MODIFIED
指示詞。SSI 指示詞可以包含在包含檔中,並且包含可以巢狀—也就是說,包含檔可以包含另一個檔,依此類推。
除了設定時間格式之外,您還可以設定其他二個項目。
通常,當您的 SSI 指示詞出錯時,您會收到「處理此指令時出錯」的訊息
[an error occurred while processing this directive]
如果您想要將此訊息改成其他訊息,您可以對config
函數使用errmsg
屬性
<!--#config errmsg="[It appears that you don't know how to use SSI]" -->
希望最終使用者永遠不會看到此訊息,因為在您的網站正式上線之前,您已解決了所有 SSI 指示詞的問題。(是這樣吧?)
您也透過sizefmt
屬性設定檔案大小傳回的格式。您可以指定bytes
取得完全的位元組計數,或指定abbrev
取得簡短的 Kb 或 Mb 數值(視情況而定)。
以下是您可以利用exec
函數執行的其他功能。您實際上可以用 shell(精確地說就是/bin/sh
)—或 DOS Shell(如果您使用 Win32)—讓 SSI 執行命令。例如,下列程式碼將提供您一個目錄清單。
<pre>
<!--#exec cmd="ls" -->
</pre>
或是在 Windows 中執行
<pre>
<!--#exec cmd="dir" -->
</pre>
在 Windows 上可能會注意到使用此指令產生一些奇怪的格式,因為從「目錄」(dir
) 輸出的內容會包含字串「<dir
>」,這會讓瀏覽器感到困惑。
請注意,這個功能非常危險,因為它會執行嵌入於 exec
標籤的任何程式碼。如果您有讓使用者能編輯網頁上內容的情形,例如以「留言簿」的方式,請務必停用此功能。使用 Options
指令的 IncludesNOEXEC
引數,您可以允許 SSI,但不允許 exec
功能。
除了顯示內容以外,Apache SSI 也提供設定變數,以及在比較和條件判斷中使用這些變數的選項。
使用 set
指令,您可以設定變數供日後使用。我們稍後會在討論中用到這個,因此我們將在這裡說明。語法如下所示:
<!--#set var="name" value="Rich" -->
除了像這樣將值設定為文字字串之外,您也可以使用其他變數,包括環境變數或上面討論的變數 (例如 LAST_MODIFIED
),來將值指定給您的變數。在變數名稱之前使用美元符號 ($),表示內容是變數而非文字字串。
<!--#set var="modified" value="$LAST_MODIFIED" -->
若要在變數值中放入一個文字美元符號,您需要使用反斜線作為美元符號的跳脫字元。
<!--#set var="cost" value="\$100" -->
最後,如果您想將一個變數置於較長的字串中間,而且變數的名稱可能會與其他字元連在一起,因此與那些字元混淆,則可以將變數的名稱置於大括號中,以消除這種混淆。(很難想出一個真正好的範例,但希望您能理解要點。)
<!--#set var="date" value="${DATE_LOCAL}_${DATE_GMT}" -->
現在我們有了變數,並能夠設定和比較它們的值,我們可以使用它們來表達條件式。這讓 SSI 成為一種微型程式語言。mod_include
模組提供一個 if
、elif
、else
、endif
結構,用於建立條件式陳述式。這允許您有效地從一個實際頁面中產生多個邏輯頁面。
這個條件式結構如下所示:
<!--#if expr="test_condition" -->
<!--#elif expr="test_condition" -->
<!--#else -->
<!--#endif -->
一個 test_condition 可以是任何類型的邏輯比較 - 無論是將值互相比較,或測試特定值的「真假」。(給定字串如果是非空的,就是真。)有關所有可用的比較運算子的完整清單,請參閱 mod_include
文件。
例如,如果您想根據一天中的時間自訂網頁上的文字,可以在 HTML 頁面中放入以下食譜
早上好 <!--#if expr="%{TIME_HOUR} <12" -->
下午好!
<!--#else -->
下午好!
<!--#endif -->
在條件式陳述句中可以使用其他變數 (您定義的變數或一般環境變數)。有關運算式評估引擎的更多資訊,請參閱 Apache HTTP Server 中的運算式。
透過 Apache 具有使用 SetEnvIf
指令和相關指令設定環境變數的功能,這個功能讓您可以在伺服器端執行各種動態內容,而不必訴諸於完整的網頁應用程式。
SSI 絕對不能取代 CGI 或用於產生動態網頁的其他技術。但它是一種極佳的方式,可以在不進行大量額外工作的情況下,將少量動態內容新增到頁面中。