緩(huan)存篇(Cache)~第三回 HttpModule實(shi)現網(wang)頁的文(wen)件級緩(huan)存
再寫完緩存篇第一回之后,得到了很多朋友的好評和來信,所以,決定加快步伐,盡快把剩下的文章寫完,本篇是第三回,主要介紹使用HttpModule實現的文件級緩存,在看本文之前,大家需要限度HttpModule有一個了解,可以先看我的這篇文章《開發人員應該對IIS理論層的知識了解的多一些~第四講 HttpModule中的幾大事件》
對于(yu)文(wen)件(jian)級緩存來(lai)說,我們要知道兩點,一為(wei)文(wen)件(jian)的(de)URL,二為(wei)文(wen)件(jian)的(de)
下面是HttpModuleCache的(de)核心代碼
/// <summary> /// CacheHttpModule類(lei) /// </summary> internal class CacheHttpModule : IHttpModule { public void Dispose() { } private List<string> listNeedCacheExtend; private string stringClearCache = "zzl";//域名中第(di)一段 url 如(ru)果(guo)是此字符,則表示此次(ci)請求是清除緩(huan)存 如(ru): //www.domain.com/zzl/******* public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(context_BeginRequest); context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState); listNeedCacheExtend = new List<string>(); string extends = WebConfig.GetUserSection("CacheInfo", "ExtendTypes", ".html|.htm"); foreach (string s in extends.Split('|')) { if (!string.IsNullOrEmpty(s) && !listNeedCacheExtend.Contains(s.Trim())) listNeedCacheExtend.Add(s.Trim()); } } public void context_BeginRequest(object sender, EventArgs e) { var application = (HttpApplication)sender; if (IsNeedCache(application)) //檢測當前請求(qiu)是否需(xu)緩存 { string key = string.Empty; ; string extend = VirtualPathUtility.GetExtension(application.Context.Request.FilePath).ToLower(); if (IsClearCache(application, out key)) { if (CacheManage.Container(key, extend))//緩存中存在,則清除緩存,結束(shu)請求 { application.Context.Response.Write(CacheManage.Remove(key, extend)); } application.CompleteRequest(); } else { #region 使用頁面壓縮 ResponseCompressionType compressionType = this.GetCompressionMode(application.Context.Request); if (compressionType != ResponseCompressionType.None) { application.Context.Response.AppendHeader("Content-Encoding", compressionType.ToString().ToLower()); if (compressionType == ResponseCompressionType.GZip) { application.Context.Response.Filter = new GZipStream(application.Context.Response.Filter, CompressionMode.Compress); } else { application.Context.Response.Filter = new DeflateStream(application.Context.Response.Filter, CompressionMode.Compress); } } #endregion if (CacheManage.Container(key, extend))//緩(huan)存中(zhong)存在,則直接(jie)返(fan)回內容,結束請求 { CacheManage.Write(application, key); application.CompleteRequest(); } } } } /// <summary> /// 檢測(ce)當前請求是否需緩(huan)存,如果是則將此(ci)次結果添加(jia)至(zhi)緩(huan)存,如果此(ci)次請求出錯,不(bu)會執行(xing)至(zhi)此(ci) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void context_ReleaseRequestState(object sender, EventArgs e) { var application = (HttpApplication)sender; if (application.Context.Response.StatusCode == 200) { string strT = null; string extend = VirtualPathUtility.GetExtension(application.Context.Request.FilePath).ToLower(); if (IsNeedCache(application) && !IsClearCache(application, out strT)) { string key = application.Context.Request.Url.AbsoluteUri; //是(shi)否需要(yao)添加緩存(cun), if (!CacheManage.Container(key, extend)) { application.Context.Response.Filter = new ResponseFilter(application.Context.Response.Filter, key, extend, application.Context.Response.ContentEncoding); } } } } public void context_EndRequest(object sender, EventArgs e) { var application = (HttpApplication)sender; string key = application.Context.Request.Url.AbsoluteUri; application.Context.Response.Write("<Br>CacheMdule EndRequest"); } /// <summary> /// 檢測當前請求類型(url擴展(zhan)名(ming))確定(ding)是否(fou)需緩存 /// 如果類型(xing)需緩存(cun),但擴展名是html或htm且存(cun)在相對(dui)應的物理文(wen)件的,不執行緩存(cun)操(cao)作 /// </summary> /// <param name="strFilePath"></param> /// <returns></returns> private bool IsNeedCache(HttpApplication application) { bool boolNeedCache = false; string stringExtend = VirtualPathUtility.GetExtension(application.Context.Request.FilePath).ToLower(); if (null != listNeedCacheExtend) //url擴展名是否滿足條件 { boolNeedCache = listNeedCacheExtend.Contains(stringExtend); } if (boolNeedCache) { if (stringExtend == ".html" || stringExtend == ".htm") { if (System.IO.File.Exists(application.Context.Request.PhysicalPath)) //存在對應物理文件 { boolNeedCache = false; } } } return boolNeedCache; } /// <summary> /// 檢測當次請求是否是清除緩(huan)存的(de) /// True 清(qing)除(chu)緩存(cun) False 不是清(qing)除(chu)緩存(cun)的(de) /// </summary> /// <param name="application"></param> /// <param name="url">真實(shi)的URL地址</param> /// <returns></returns> private bool IsClearCache(HttpApplication application, out string url) { bool boolClearCache = false; url = application.Context.Request.Url.AbsoluteUri; string domain = application.Context.Request.Url.Host; Regex regex = new Regex("//" + domain + "/" + stringClearCache + "/", RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase); if (regex.IsMatch(url)) { boolClearCache = true; url = "//" + domain + "/" + url.Replace(regex.Match(url).Captures[0].Value, string.Empty); } return boolClearCache; } /// <summary> /// 獲取(qu)客(ke)戶端支持(chi)的壓縮類型 /// </summary> /// <param name="request"></param> /// <returns></returns> private ResponseCompressionType GetCompressionMode(System.Web.HttpRequest request) { string acceptEncoding = request.Headers["Accept-Encoding"]; if (string.IsNullOrEmpty(acceptEncoding)) return ResponseCompressionType.None; acceptEncoding = acceptEncoding.ToUpperInvariant(); if (acceptEncoding.Contains("GZIP")) return ResponseCompressionType.GZip; else if (acceptEncoding.Contains("DEFLATE")) return ResponseCompressionType.Deflate; else return ResponseCompressionType.None; } private enum ResponseCompressionType { None, GZip, Deflate } }
對于上(shang)面的(de)HttpModule來說,還需要在config文(wen)件中進行相應的(de)配置,代碼如下(xia)
<modules runAllManagedModulesForAllRequests="true" > <add name="CacheHttpModule" type="HttpModuleCache.CacheHttpModule,HttpModuleCache"/> </modules>
程序運行后(hou)當(dang)檢測到(dao)合法的(de)文(wen)件后(hou)(如你(ni)之前(qian)對(dui)html和shtml結尾的(de)文(wen)件進(jin)行緩(huan)存(cun)),就會生成文(wen)件到(dao)服(fu)(fu)務器的(de)指(zhi)定位(wei)置(zhi),下次訪問(wen)時,直接通過(guo)URL生成的(de)服(fu)(fu)務器本地路(lu)徑,將靜態文(wen)件返回(hui)到(dao)客戶(hu)端(duan)即可,不過(guo),有個地方要(yao)注意,由于這種方法生成的(de)緩(huan)存(cun)文(wen)件,它(ta)的(de)位(wei)置(zhi)不是固(gu)定的(de),所(suo)以,在引用CSS,JS這種文(wen)件時,要(yao)用絕(jue)對(dui)路(lu)徑的(de)形式。
沒有用絕對路徑時
用了絕對路徑后
怎(zen)么樣,這種文件級緩存的方式大(da)家都掌(zhang)握(wo)了吧!