需求背景
平時在web開發中,對於shtml頁面,用得最多的SSI指令是include。語法規則如下:
<!–#include virtual=”shtmlCache/header.shtml” –>
這樣可提高代碼重用性以及可維護性,因此,一般都把公共文件,如頭部、尾部、側邊欄、公共的JS等做成一個單獨的文件,然後通過include指令包含進來,這樣整個站點的頭部、尾部、側邊欄、公共JS等,都可以被引入到shtml頁面中。後面需求更改,比如產品需要更改站點頭部,也只需要更改頭部文件,就可以實現全站頭部更新。可見通過include指令包含公共文件,可以使shtml頁面的維護性和重用性大大增強。
一般來說,對於shtml頁面,一個站點,每個頁面都會有相同的公共文件,比如頁面的頭部、尾部、側邊欄目、公共JS等。訪問站點下的每一個頁面,相同的公共文件,都需要重復從服務器下載。從性能和帶寬角度看,重復下載相同內容對性能不利,同時也會占用帶寬。因此include進來的公共文件,是否有辦法緩存這些文件呢?這就是這裡需要重點討論的內容。 假設有這樣一個站點,包含有頁面頭部、側邊欄、頁面尾部、公共JS。布局如下圖:
從上面的網頁布局結構可看出,頁頭、側邊欄、頁尾都是屬於公共的內容,HTML 代碼樁如下:
實現原理:
需要判斷include的文件是否緩存過,如果緩存過,則不會通過include來包含對應的內容。ssi有判斷的指令,語法如下:
<!–#if expr=”test_condition” –>
< !–#elif expr=”test_condition” –>
< !–#else –>
< !–#endif –>
我們可通過SSI指令來判斷是否緩存過。同時可利用html5的localStorage來對代碼進行保存。
可localStorage只能夠通過JS訪問,那如何實現localStorage和服務器的ssi指令通信呢?這裡利用到一個小技巧,借助cookie作為橋梁,不管是JS還是SSI都是可以訪問,因此可利用它來實現SSI和JS之間的通信。換言之,用JS寫一個cookie來標識是否已經緩存過相應的內容,然後利用SSI的if語句結合cookie來判斷是否需要include對應的內容。
主要流程圖如下:
示例分析:
來看一個簡單的demo。以前面頁面框架為例,假設header裡面有內容是通過JS來輸出,側邊欄是全部的HTML,現在要緩存header中的JS和側邊欄的HTML。先來看核心的HTML代碼(SSI部分):
再看JS寫入緩存核心代碼:
localData.loadfromCache是實現從localStorage讀取緩存並渲染出來,這個比較簡單,這裡就不再單獨介紹或者放在支持ssi的服務器下運行。第一次訪問後,將會把對應的公共文件進行緩存,先查看解析後的HTML源代碼:
從上圖可以看出,第一次訪問時,因沒有緩存過,都是通過include進行直接解析。同時通過cookie和localStorage可查看到相應的值。
cookie信息:
localStorage信息:
第二次訪問時,再查看解析後的HTML源代碼
從上面的2個圖對比可以看出,當公共文件沒有被緩存時,是通過解析include指令得到相應的代碼;當有緩存時,直接通過JS代碼從緩存中讀取;從而實現shtml文件局部緩存;
版本控制:
上述示例演示了shtml的局部緩存,那麼緩存的版本如何控制呢?可通過cookie來保存版本號,當有緩存的公共文件需要更新時,需要更新ssi if語句中的的版本號,也就是更新下面這行代碼中的版本號:
<!–#if expr=”${HTTP_COOKIE} = /(;)?html_aside=01(;)?/”–>
假設上一個版本號是01,現在版本號是02,此時需要把上述代碼更改為:
<!–#if expr=”${HTTP_COOKIE} = /(;)?html_aside=02(;)?/”–>
當從SSI中讀取到的cookie值和新的版本號不一致時,就不會從緩存中讀取了。同理在檢測寫入緩存時,也需要檢測當前cookie的值和當前的版本號是否一致即可,如果不一致,則需要重新寫入緩存。
安全控制
這裡把JS和HTML等代碼都緩存到localStorage中去,如果網站中存在XSS漏洞,則攻擊者可利用XSS漏洞篡改localStorage保存的數據,這樣會擴大網站的危害性,因此首先要從源頭上控制好XSS漏洞,同時也需要對從localStorage中讀取出來的數據進行合法性校驗,以便降低安全風險。大家可以自行設計一個算法來檢測數據的合法性。
上面的示例中只是對簡單的header中的JS和側邊欄的HTML進行緩存,在實際項目中,需要緩存的JS和HTML代碼量要比示例中大得多,因此性能優化的實際效果也會更加明顯。因此在實際項目中,可根據公共文件的大小來決定是否需要使用shtml緩存。另外,關於緩存時間,只需要把cookie的有效期設置為N天,則緩存的周期就變成N天了,非常靈活!