SSI(Server Side Includes),是嵌套在 HTML 網頁中的指示語句,由後臺服務器進行代碼的解釋計算。使用 SSI 能夠動態的建立一部分網頁內容而不須要編寫複雜的 JSP/ASP/PHP 等程序。SSI 是如此的小巧以致於不該算做一門語言,由於他遠沒有JSP/ASP/PHP 等程序那麼複雜,只有一些極其有限的語法規則。javascript
不少 HTTP Server 程序都支持 SSI,可能語法稍有不一樣,好比: IIS/Novell HTTP Server 等等,大同小異,本文要說明的是 Apache 2.0 的 SSI。閒話少說,我想告訴你們的是,這是一篇實踐經驗總結性的文章,後文中的示例解決方案都是來自實際的網站應用中。php
<Directory "D:/myProject/web"> AddType text/html .ssi #這裏能夠是 .shtml 或其餘 不必定要 .ssi, 設置.ssi後綴的也是text/html類型的文件 Options Includes AddOutputFilterByType INCLUDES; DEFLATE text/html #輸出處理器 </Directory>
測試SSI是否成功啓用 編輯文件html
// test.ssi : # echo指令輸出變量 DATE_LOCAL <!--#echo var="DATE_LOCAL" --> ## 特別注意 <!--# 之間不能有任何空格,否則指令是無效的,被看成html註釋
由於不少IDE都有註釋代碼行的快捷鍵, 如 sublime text( ctrl + /) 可是會變成 <!-- #echo var="..." -->
,因爲多了個空格,因此ssi指令被當成註釋了。 java
瀏覽器訪問 http://localhost/test.ssi 能看到打印當前時間 說明SSI已啓用web
這些文檔也能夠在 Apache的安裝文件夾找到:
Apache Tutorial: Introduction to Server Side Includes
Apache mod_include正則表達式
<!--#fn attribute=value attribute=value ... -->
fn能夠理解成函數或者指令。 例子:express
#環境變量習慣大寫 http://<!--#echo var="SERVER_NAME" var="DOCUMENT_URI"--> #virtual的值能夠是相對路徑或絕對路徑 如 virtual="/ssi/footer.ssi" <!--#include virtual="ssi/footer.ssi" --> #file的值只能是相對路徑 <!--#include file="footer.ssi" --> #設置自定義變量 <!--#set var="protocol" value="http" -->
SSI 語句是直接嵌套在 HTML 頁面中的,能夠放置在任意的位置。因此 SSI 語句先後採用 HTML 註釋的寫法,這樣一旦服務器關閉了對 SSI 的支持,此時訪問頁面的話,也不會直接在網頁上顯示出沒必要要的代碼。apache
SSI不區分大小寫,環境變量用大寫是很好的習慣;
SSI中只有一種數據類型:字符串;
SSI中的轉義符是 ,字符串能夠用雙引號或單引號包裹 ,同JS瀏覽器
自定義變量使用 set 命令來建立:<!--#set var="protocol" value="http" -->
環境變量是系統已經存在的一些默認的變量和變量值,能夠直接使用。 <!--#echo var=」DATE_LOCAL」 -->
DATE_LOCAL 就是一個環境變量,用來顯示當前本地時間。相似的環境變量還有不少,好比經常使用HTTP_HOST、SERVER_NAME、DOCUMENT_URI、DOCUMENT_NAME 等等。安全
# 查看全部環境變量 # 因爲無換行因此按ctrl+u,以網頁源代碼的方式查看更清晰點 <!--#printenv--> # ------- 應用示例: -------------- <body> <!--#include virtual="/bnn/ssi/header.ssi"--> <div id="Main"> <div id="Content"> <p>This is "<a href="http://<!--#echo var='SERVER_NAME' -->">Learning Apache SSI</a>" testing page!</p> <p>Hello SSI</p> <p>Today is: <!--#echo var="DATE_LOCAL" --></p> </div> </div> <!--#include virtual="ssi/footer.ssi"--> </body>
<!--#set var=」MyFirstVar」 value=」120」 --> <!--#set var=」MySecondVar」 value=」20」 --> # $MyFirstVar < $MySecondVar //由於2個變量都是字符串值 因此執行的是字符串比較(比較每一個字符的ASCII碼大小)
SSI 的元素並很少,下面列出經常使用的元素和屬性,其它請查看官方參考。
#能夠一次輸出多個變量值 <!--#echo var="DATE_LOCAL"--> http://<!--#echo var=」SERVER_NAME」 var=」DOCUMENT_URI」 -->
include 是 SSI 中最經常使用的命令,也是 SSI 主要功能的體現。
# virtual的值能夠是相對路徑或絕對路徑, 但注意路徑中不能包含主機名; #路徑能夠是相對當前文件(SSI 語句所在的頁面)或者從「/」開始,相對網站根目錄的路徑; <!--#include virtual="ssi/header.ssi"--> # 路徑後容許加參數 <!--#include virtual="/cgi-bin/ap/optin_cn.pl?btn=send&fax=yes" -->
SSI 是容許嵌套的;例如,假設有三個文件,file1 include file2,file2中 include file3。
<!--#set var=」Protocol」 value=」http」 --> # 若變量值帶引號,能夠這樣: <!--#set var="MyVar1" value='"IBM"' --> //value的值能夠是字符串常量或者變量 如:value="$MyVar2" <!--#set var="MyVar2" value="\"IBM\"" -->
SSI中的變量都帶$前綴 如:$Myvar,爲了更清晰的表達一個變量 一般用大括號把變量名包起來 ${MyVar} , 同php
<!--#set var="MyVar1" value="IBM" --> <!--#set var="MyVar2" value="Services" --> <!--#set var="MyVar3" value="${MyVar1}${MyVar2}" --> //設置 MyVar3 = MyVar1+MyVar2 <!--#echo var="MyVar3" --> <!--#set var="MyVar3" value="abc${MyVar1}_${MyVar1}def" --> // 修改MyVar3的值 <!--#echo var="MyVar3" --> <!--#set var=」MyVar1」 value=」IBM」 --> <!--#set var=」MyVar2」 value=」\$MyVar1」 --> // 變量值爲 "$IBM" # 另外一個把變量寫在 SSI 語句中的例子: <!--#include virtual="/servers/eserver/${cc}/ssi/nav_left.ssi" --> // 這個比較有用。
顯示指定文件的大小(fsize)和指定文件的最後修改時間(flastmod)
virtual
– 與元素 include 中的屬性相同,<!--#fsize virtual=」/cgi-bin/cmail.pl」 -->
結果返回的是這個 Perl 腳本文件的大小,而不是運行這段 Perl 腳本的結果。
config指令
配置一些 SSI 運行結果;錯誤信息、文件大小格式、時間格式。
errmsg屬性 當 SSI 語句運行出錯時顯示的信息。 例如:<!--#config errmsg="出錯啦# " -->
sizefmt 顯示以何種方式顯示文件大小。這個屬性有兩個值:bytes 和 abbrev。
<!--#config sizefmt="bytes" --> //按bytes大小顯示 <!--#config sizefmt="abbrev" --> //按bytes、Kb或Mb動態顯示 視文件大小
timefmt 顯示時間的格式。屬性值的參數同 C 標準庫中的strftime(3) 相同;
<!--#config timefmt="%Y-%m-%d"--> <!--#config timefmt="%Y-%m-%d"--> <meta name="DC.DATE" scheme="iso8610" content="<!--#echo var=’LAST_MODIFIED’-->">
SSI 中只有條件語句一種結構,並且結構很簡單。基本的控制元素:
<!--#if expr="test_condition"--> html or SSI statements <!--#elif expr="test_condition"--> html or SSI statements <!--#else--> html or SSI statements <!--#endif--> ## if 語句能夠嵌套,你能夠在 if 塊中再加入一個 if 塊語句。
非空字符串爲真,空串爲假
<!--#if expr="IBM" --> // 表示條件成立; <!--#if expr="" --> //空字符,返回 假,條件不成立。
判斷一個變量是否爲空字符串的一種寫法:<!--#if expr="$MyVar = ‘’" -->
<!--#if expr="$DOCUMENT_URI = ‘/bnn/index.html’" --> codes <!--#endif -->
運算符優先級 比較運算符優先級高於邏輯運算符 ; && 和 || 具備相同的優先級,可使用括號 () 進行分組。
<!--#if expr="$a = test1 && $b = test2" --> <!--#if expr="($a = test1) && ($b = test2)" -->
任何不被識別爲變量或者操做符都被看成是一個字符串。字符串也可使用引號(單引號或者雙引號)括起來。不被引號括起來的字符串中不容許有空格或者 Tab,由於空格是被用來起到分隔的做用。若是一個字符串中包含空格,請使用引號括起來。
<!--#if expr="$a = test1 && $b = ‘test 2’" -->
Regular expression (正則表達式,縮寫 RE),是一種對字符串進行匹配查找的高效模式。幾乎每一種語言都支持 RE;Apache SSI 中的 RE 語法同 Perl(版本 5)語言中的相同,但並不完整的支持
<!--#if expr="$QUERY_STRING = /^sid=([a-zA-Z0-9]+)/" --> <!--#set var="session" value="$1" --> <!--#endif -->
說明:此例表示從參數中提取子字符串。$QUERY_STRING 是環境變量,表示經過網頁 URL 傳遞過來的參數,例如:
http://www.IBM.com/index.html?sid=safsaf43513sadfz&cntry=cn
其中,問號後面的部分就是 $QUERY_STRING 的值。
若是等號右邊的比較部分是 / / 這種形式,則表示,這部分是正則表達式
/^sid=([a-zA-Z0-9]+)/ 括號表示分組,用圓括號分組的同時,程序自動會將圓括號內匹配的部分提取出來保存在 $1 這個變量中;這個 $1 是系統變量,用來保存正則表達式分組提取出來的各個部分值,一共有 9個,$1-$9。
SSI 與 JS 如何一塊兒使用呢?是這樣的,因爲服務器並不能識別 JS 代碼,因此能夠把 SSI 語句放到 JS 代碼行中,這樣取代一部分 JS 代碼的工做,將這部分工做放到服務器端運行。
<!--#if expr="$DOCUMENT_URI = /\/bnn\//" --> //正則匹配 形如:/bnn/ 的路徑,而後設置變量 SSI變量在JS中輸出 <!--#set var="LASLink" value="http://localhost/bnn/" --> <!--#set var="LASText" value="Learning Apache SSI" --> <!--#endif --> <script type="text/javascript"> //<![CDATA[ document.write(‘<a class="fbox" href="<!--#echo var="LASLink" -->"><!--#echo var="LASText" --></a>’); //]]> </script>
前幾天遇到這樣一個需求:一個 Promotion - 3月3日以前顯示默認的內容,3月3日以後顯示另一個內容。下面給出這段代碼,分享一下相似這種的要求該如何入手。
<!--#config timefmt="%Y-%m-%d"--> # 配置日期格式 <!--#if expr="$DATE_LOCAL = /(.+)-(.+)-(.+)/" --> # 流程控制語句實現邏輯 正則匹配當前本地日期 捕獲年月日 <!--#if expr="($2 = '03') && ($3 != /0[1-3]/)" --> # 嵌套的if 正則跟字符串比較? 3月3日以後 <!--#else --> 默認 <!--#endif --> <!--#endif -->
頁面佈局中一些相對固定的模塊,能夠經過include的方式包含到頁面中。
一般狀況下,上面有 4個區域是不常常變更的:Header、Left Nav、Nav Trail 和 Footer。
<body> <!--#include virtual="ssi/header.ssi"--> # 把頭部模塊包含進來 <div id="Main"> <div id="LeftNav"><!--#include virtual="ssi/nav_left.ssi"--></div> # 左側導航模塊包含進來 <div id="RightNav"><!--#include virtual="ssi/nav_right.ssi"--></div> # ~右側導航模塊include進來 <div id="Content"> <div id="NavTrail"><!--#include virtual="ssi/nav_trail.ssi"--></div> # 麪包屑模塊include進來 <p>Hello SSI</p> </div> </div> <!--#include virtual="ssi/footer.ssi"--> # 頁腳模塊include進來 </body> <!--#set var="protocol" value="" --> # 設置變量protocol初始值 <!--#if expr="$HTTPS != /ON/" --> # 若環境變量$HTTPS 開啓,則設置變量protocol的值 <!--#set var="protocol" value="http://${SERVER_NAME}" --> <!--#endif --> <!--#set var="protocols" value="https://${SERVER_NAME}" --> # 設置變量 變量名比較長的話用大括號包起來比較清晰,易於解析。 # 根據請求的路徑 高亮顯示相應的欄目連接 <ul> <li class="TopLink"> <a class="left-nav-overview" href="<!--#echo var='protocol' -->/ ">IBM</a> </li> <li class="PrimaryLink<!--#if expr='$DOCUMENT_URI = /\/systems\/cn\//' -->-Highlight<!--#endif -->"> <a class="left-nav" href="<!--#echo var='protocol' -->/systems/cn/">Systems</a> </li> <li class="PrimaryLink<!--#if expr='$DOCUMENT_URI = /\/contact\/index.html/' -->-Highlight<!--#endif -->"> <a class="left-nav" href="<!--#echo var='protocols' -->/contact/index.html">聯繫咱們</a> </li> </ul>
Nav Trail 又叫作 Breadcrumb,中文裏咱們叫作「當前位置」。在頁面上,根據當前頁面所在不一樣,在這個地方會有提示訪問者當前所在的位置。若是在每一個頁面都存在這個提示的話,編輯起來會很麻煩。但如今可使用 SSI 解決這個問題,只要在每一個頁面的這個位置 include 一個 SSI 文件就能夠了,當前所在位置的工做交給 SSI 來完成。
<!--#set var="protocol" value="" --> # 設置變量protocol初始值 <!--#if expr="$HTTPS != /ON/" --> # 若url是 https:// 安全訪問模式 <!--#set var="protocol" value="http://${SERVER_NAME}" --> # 設置變量 protocol的值 <!--#endif --> <!--#set var="protocols" value="https://${SERVER_NAME}" --> # 設置一系列變量值 當前位置的連接和文本 <!--#set var="NavTrailLink1" value="" --> <!--#set var="NavTrailLinkName1" value="" --> <!--#set var="NavTrailLink2" value="" --> <!--#set var="NavTrailLinkName2" value="" --> <!--#set var="NavTrailLink3" value="" --> <!--#set var="NavTrailLinkName3" value="" --> # 設置值時是多重if嵌套 <!--#if expr="$DOCUMENT_URI = /\/bnn\// && $DOCUMENT_URI != /\/bnn\/index.html/" --> # 如果訪問/bnn/下非index.html頁面 <!--#set var="NavTrailLink1" value="${protocol}/bnn/" --> # 設置一級文本和連接變量值 <!--#set var="NavTrailLinkName1" value="BNN" --> <!--#if expr="$DOCUMENT_URI = /\/bnn\/books\// && $DOCUMENT_URI != /\/bnn\/books\/index.html/" --> # 如果訪問/bnn/books/下非index.html頁面 <!--#set var="NavTrailLink2" value="${protocol}/bnn/books/" --> # 設置二級文本和連接變量值 如此類推 <!--#set var="NavTrailLinkName2" value="圖書館" --> <!--#elif expr="$DOCUMENT_URI = /\/bnn\/food\// && $DOCUMENT_URI != /\/bnn\/food\/index.html/" --> <!--#set var="NavTrailLink2" value="${protocol}/bnn/food/" --> <!--#set var="NavTrailLinkName2" value="好吃的" --> <!--#if expr="$DOCUMENT_URI = /\/bnn\/food\/strawberry\// && $DOCUMENT_URI != /\/bnn\/food\/strawberry\/index.html/" --> <!--#set var="NavTrailLink3" value="${protocol}/bnn/food/strawberry/" --> <!--#set var="NavTrailLinkName3" value="草莓" --> <!--#endif --> <!--#endif --> <!--#endif --> # 輸出當前位置時也是多重if嵌套 <img alt="" class="display-img" height="6" src="//www.ibm.com/i/c.gif" width="1" /> <!--#if expr="$NavTrailLink1" --> <a class="bctl" href="<!--#echo var='NavTrailLink1' -->"><!--#echo var="NavTrailLinkName1" --></a><span class="bct"> > </span> <!--#if expr="$NavTrailLink2" --> <a class="bctl" href="<!--#echo var='NavTrailLink2' -->"><!--#echo var="NavTrailLinkName2" --></a><span class="bct"> > </span> <!--#if expr="$NavTrailLink3" --> <a class="bctl" href="<!--#echo var='NavTrailLink3' -->"><!--#echo var="NavTrailLinkName3" --></a><span class="bct"> > </span> <!--#endif --> <!--#endif --> <!--#endif -->
語法: <!--#directive [parm=value] -->
,指令包括:
config
:設置日期格式等,如:(<!--#config timefmt="%B %Y" -->
)echo
:打印變量值 (<!--#echo var="VARIABLE_NAEM" -->
)exec
:用來執行服務器端的命令include
:文件包含 (<!--#include virtual="file-name" -->
)flastmod
:輸出指定文件最後修改時間(<!--#flastmod file="filename.shtml" -->
)fsize
:輸出指定文件的大小(<!--#fzie file="filename.shtml" -->
)printenv
:打印全部環境變量(<!--#printenv -->
)set
:設置或修改變量 (<!--#set var="foo" value="Bar" -->
)if elif endif else
:建立條件分支