一、引言
1、爲什麼,csdn的帖子後面要加個temp查詢字符串。
2、爲什麼,同一個帖子,“temp”查詢字符串會經常發生變化。
3、爲什麼,Internet緩存目錄會過度膨脹。
二、背景
CSDN帖子採用xml文件進行存儲,下載時也直接下載xml文件。這樣做有許多好處。比如,1、實現數據與顯示的分離:數據的更新與顯示頁面的維護都非常方便;2、減少網絡傳輸:顯示頁面(xsl文件)只需要下載一次,數據文件(xml文件)也非常的短小,因此帖子打開顯示的速度很快。
但使用xml文件同時要考慮一個緩存的問題。由於xml文件是一個靜態文件,當瀏覽器第一次訪問之後,會將其緩存至臨時目錄,下一次訪問時,可能不會再訪問服務器,而直接從緩存讀取。如果在真實的URL地址後面加上臨時的、隨機的查詢字串,那麼瀏覽器通過這個URL在緩存中找不到,就會訪問服務器,讀取最新的數據。
大家可以測試一下,隨便在“temp=”後面輸入任何數字,或直接將“temp=”刪除,都會訪問到xml文件。爲了保證用戶總是能通過不同的URL訪問最新的帖子,至少存在以下兩個機制:
- 不直接提供形如“xml?temp=xxxx”的URL(簡稱“地址A”),而是提供形如“topicview1.asp?id=4854274”的URL(簡稱“地址B”)。地址B,瀏覽器不緩存,總是能訪問服務器,而服務器則根據需要生成隨機的地址A,傳給瀏覽器,通過重定向,取得最新的xml文件。
- 爲了避免頻繁的改變地址A,至少當帖子更新後,必須重新生成一個temp查詢字符串。
三、兩難境地
基於以上的分析,訪問同一個帖子,將會對應地產生多個地址A,也就會在瀏覽器的臨時目錄中緩存多個帖子副本。顯然,只有最後一個副本有意義(脫機時),以前的是多餘的,不再可能被訪問的。可能有人會想,爲什麼不通過在服務器端設置頭部“Cache-Control:no-cache”,從而阻止瀏覽器緩存xml文件呢?一個簡單的理由是,爲了支持在脫機時能夠訪問以前訪問過的xml文件,必須使用緩存。
於是,這將出現一個兩難境地。如果爲了節約緩存,那麼就不會使用“temp”這項技術,就有可能不能訪問最新的數據;如果爲了總是能訪問到最新的數據,就會在臨時目錄緩存大量重複的數據。
四、解決方案
“CSDN助手”通過一個橋接技術,很好的解決了這個“兩難問題”。
舉例:
地址A:http://community.csdn.net/Expert/topic/4854/4854274.xml?temp=.5251428
地址B:http://community.csdn.net/expert/topicview1.asp?id=4854274
地址C:http://community.csdn.net/expert/cache/4854274.xml
- 截獲瀏覽器對“地址A”和“地址B”的訪問,通過URL Moniker技術,自己訪問服務器,取得數據文件後,以“地址C”的名義緩存至臨時目錄。這樣,當瀏覽器再次訪問“地址A”和“地址B”時,由於在緩存中找不到,所以仍然會再次訪問服務器。而“地址C”針對同一個帖子是唯一的,所以確保緩存中只有唯一的副本。
- 怎樣支持脫機:截獲瀏覽器對“地址A”和“地址B”的訪問,先判斷是否處於脫機狀態。如不是,則進行步驟1;如是,則通過“地址C”在緩存中找到副本直接打開。
五、URL Moniker
前面講到,截獲瀏覽器對“地址A”和“地址B”的訪問,自己訪問服務器,從而有效的控制緩存的處理。自己訪問服務器,讀取數據文件,可以有多種技術。我們分析一下他們的特點,決定到底用哪一種技術:
- Socket函數:最底層(也是相對而言)的訪問方法,需要構造Request,分解Response,需要編碼、解碼,而且不支持系統提供的通過代理訪問服務器的能力。
- wininet函數:系統級的函數,支持代理,靈活性強,但考慮的細節過多。
- Msxml2.XMLHTTP組件:封裝了許多細節,調用方便,但不支持客戶端對緩存的控制。有許多人在進行Ajax開發時,對這個組件“不支持客戶端緩存控制”的特點頗有微詞。對緩存的控制,經常需要服務器的配合。顯然,開發“CSDN助手”不應該對服務器要求過多。
- URL Moniker對象:URL Moniker提供了一種建立並使用URL的框架,初次接觸時感覺不太好理解,但實際上很好控制,支持代理,支持客戶端的緩存控制,相對wininet函數而言,細節比較少。
事實上,在“CSDN助手”的早期版本,由於沒有過多考慮“緩存優化”的細節,採用了“Msxml2.XMLHTTP組件”進行數據的讀取。由於組件的自身限制,不得不在其他的幾項技術中選中了“URL Moniker對象”。
關於“URL Moniker對象”的實現細節,請參考
六、相關函數
爲節省篇幅,下面僅列出主要的函數與方法,便於“下斷點跟蹤”,源碼下載請轉到:http://blog.csdn.net/seasol/archive/2006/07/04/873747.aspx
- function fn_shell_callback(oWindow,oUrl,oTarget)
位於“程序集/CSDNAssist/default.asps”文件中,用於截獲瀏覽器對“地址A”和“地址B”的訪問。 - CCSDNTools::topicviewPrecheck(BSTR bstrURL, BSTR* pbstrValue)
檢測是否處於脫機狀態,如果是,則直接返回緩存中的副本。 - CCSDNTools::topicview(BSTR bstrUrl,VARIANT varDisp, BSTR bstrTarget, long nType,IDispatch* pDispCallback)
啓動帖子的異步下載。 - CCSDNTools::func_topicviewResponseProc(void* pParam1,CParam_Http_Base* pParam2,CCuteHttpBase* pHttpBase,IStream* pStream)
當帖子下載完成時調用的回調函數。 - CCSDNTools::SaveToCache(IStream* pStream,LPCTSTR szUrl,LPCTSTR szUrlCache,LPCTSTR szTopicID,CString& sCacheFile)
將帖子緩存至Internet臨時目錄。