缓存篇(Cache)~第三回 HttpModule实现网页的文件级缓存

简介:

再写完缓存篇第一回之后,得到了很多朋友的好评和来信,所以,决定加快步伐,尽快把剩下的文章写完,本篇是第三回,主要介绍使用HttpModule实现的文件级缓存,在看本文之前,大家需要限度HttpModule有一个了解,可以先看我的这篇文章《开发人员应该对IIS理论层的知识了解的多一些~第四讲 HttpModule中的几大事件》

对于文件级缓存来说,我们要知道两点,一为文件的URL,二为文件的

下面是HttpModuleCache的核心代码

/// <summary>
    /// CacheHttpModule类
    /// </summary>
    internal class CacheHttpModule : IHttpModule
    {
        public void Dispose()
        {
        }
        private List<string> listNeedCacheExtend;
        private string stringClearCache = "zzl";//域名中第一段 url 如果是此字符,则表示此次请求是清除缓存 如: http://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)) //检测当前请求是否需缓存
            {
                string key = string.Empty; ;
                string extend = VirtualPathUtility.GetExtension(application.Context.Request.FilePath).ToLower();
                if (IsClearCache(application, out key))
                {
                    if (CacheManage.Container(key, extend))//缓存中存在,则清除缓存,结束请求
                    {
                        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))//缓存中存在,则直接返回内容,结束请求
                    {
                        CacheManage.Write(application, key);
                        application.CompleteRequest();
                    }
                }



            }
        }

        /// <summary>
        /// 检测当前请求是否需缓存,如果是则将此次结果添加至缓存,如果此次请求出错,不会执行至此
        /// </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;
                    //是否需要添加缓存,
                    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扩展名)确定是否需缓存
        /// 如果类型需缓存,但扩展名是html或htm且存在相对应的物理文件的,不执行缓存操作
        /// </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>
        /// 检测当次请求是否是清除缓存的 
        /// True 清除缓存  False  不是清除缓存的
        /// </summary>
        /// <param name="application"></param>
        /// <param name="url">真实的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("http://" + domain + "/" + stringClearCache + "/", RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
            if (regex.IsMatch(url))
            {
                boolClearCache = true;
                url = "http://" + domain + "/" + url.Replace(regex.Match(url).Captures[0].Value, string.Empty);
            }
            return boolClearCache;
        }


        /// <summary>
        /// 获取客户端支持的压缩类型
        /// </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
        }

    }

对于上面的HttpModule来说,还需要在config文件中进行相应的配置,代码如下

  <modules runAllManagedModulesForAllRequests="true" >
      <add name="CacheHttpModule" type="HttpModuleCache.CacheHttpModule,HttpModuleCache"/>
    </modules>

程序运行后当检测到合法的文件后(如你之前对html和shtml结尾的文件进行缓存),就会生成文件到服务器的指定位置,下次访问时,直接通过URL生成的服务器本地路径,将静态文件返回到客户端即可,不过,有个地方要注意,由于这种方法生成的缓存文件,它的位置不是固定的,所以,在引用CSS,JS这种文件时,要用绝对路径的形式。

没有用绝对路径时

用了绝对路径后

怎么样,这种文件级缓存的方式大家都掌握了吧!

下载完整HttpModuleCache项目

本文转自博客园张占岭(仓储大叔)的博客,原文链接:缓存篇(Cache)~第三回 HttpModule实现网页的文件级缓存,如需转载请自行联系原博主。

目录
相关文章
|
9月前
|
缓存 监控 Linux
Linux系统清理缓存(buff/cache)的有效方法。
总结而言,在大多数情形下你不必担心Linux中buffer与cache占用过多内存在影响到其他程序运行;因为当程序请求更多内存在没有足够可用资源时,Linux会自行调整其占有量。只有当你明确知道当前环境与需求并希望立即回收这部分资源给即将运行重负载任务之前才考虑上述方法去主动干预。
2327 10
|
存储 缓存 NoSQL
【Azure Redis 缓存】关于Azure Cache for Redis 服务在传输和存储键值对(Key/Value)的加密问题
【Azure Redis 缓存】关于Azure Cache for Redis 服务在传输和存储键值对(Key/Value)的加密问题
335 2
|
10月前
|
存储 缓存 NoSQL
Spring Cache缓存框架
Spring Cache是Spring体系下的标准化缓存框架,支持多种缓存(如Redis、EhCache、Caffeine),可独立或组合使用。其优势包括平滑迁移、注解与编程两种使用方式,以及高度解耦和灵活管理。通过动态代理实现缓存操作,适用于不同业务场景。
716 0
|
11月前
|
存储 缓存
.NET 6中Startup.cs文件注入本地缓存策略与服务生命周期管理实践:AddTransient, AddScoped, AddSingleton。
记住,选择正确的服务生命周期并妥善管理它们是至关重要的,因为它们直接影响你的应用程序的性能和行为。就像一个成功的建筑工地,工具箱如果整理得当,工具选择和使用得当,工地的整体效率将会大大提高。
363 0
|
存储 数据挖掘 虚拟化
vsan数据恢复—vsan缓存盘故障导致虚拟机磁盘文件丢失的数据恢复案例
VMware vsan架构采用2+1模式。每台设备只有一个磁盘组(7+1),缓存盘的大小为240GB,容量盘的大小为1.2TB。 由于其中一台主机(0号组设备)的缓存盘出现故障,导致VMware虚拟化环境中搭建的2台虚拟机的磁盘文件(vmdk)丢失。
|
SQL 缓存 Java
JVM知识体系学习三:class文件初始化过程、硬件层数据一致性(硬件层)、缓存行、指令乱序执行问题、如何保证不乱序(volatile等)
这篇文章详细介绍了JVM中类文件的初始化过程、硬件层面的数据一致性问题、缓存行和伪共享、指令乱序执行问题,以及如何通过`volatile`关键字和`synchronized`关键字来保证数据的有序性和可见性。
254 3
|
缓存 JavaScript 开发者
网页离线缓存 Service Worke
网页离线缓存 Service Worke
668 4
|
缓存 NoSQL Redis
【Azure Redis 缓存】Azure Cache for Redis 服务的导出RDB文件无法在自建的Redis服务中导入
【Azure Redis 缓存】Azure Cache for Redis 服务的导出RDB文件无法在自建的Redis服务中导入
223 0
|
缓存 开发框架 NoSQL
【Azure Redis 缓存】VM 里的 Redis 能直接迁移到 Azure Cache for Redis ? 需要改动代码吗?
【Azure Redis 缓存】VM 里的 Redis 能直接迁移到 Azure Cache for Redis ? 需要改动代码吗?
219 0
|
缓存 前端开发 Java
【Azure 应用服务】App Service 使用Tomcat运行Java应用,如何设置前端网页缓存的相应参数呢(-Xms512m -Xmx1204m)?
【Azure 应用服务】App Service 使用Tomcat运行Java应用,如何设置前端网页缓存的相应参数呢(-Xms512m -Xmx1204m)?
245 0