zoukankan      html  css  js  c++  java
  • 一个具有缓存数据功能的HttpWebRequest工具类

    背景:一个公共站点中的数据,供其它子站点共享,为了提高性能,简单实现了Http 1.1的缓存功能

    特点:可以缓存Html数据到内存中;缓存具有过期时间;缓存过期后,通过再确认的方式来决定是否更新缓存;浏览器刷新后,无论缓存是否过期都会强制再验证;

    未实现的包括:不能通过no-store来强制清空缓存,缓存再确认时没有验证Etag

    /// <summary>
        /// 启用缓存的HttpRequest
        /// </summary>
        public static class CacheHttpRequest
        {
            private static Dictionary<String,HtmlLocalCache> _caches = new Dictionary<string,HtmlLocalCache>();
            private static object AddCacheLock = new Object();
    
            public static String GetHtml(String url)
            {
                HtmlLocalCache cache;
                //如果有缓存,且缓存尚未过期,或不需要重新验证,则直接返回内容
                if(_caches.TryGetValue(url,out cache))
                {
                    if(!cache.NeedRevalidate())
                    {
                        return cache.Html;
                    }
                }
    
                var webRequest = (HttpWebRequest)WebRequest.Create(url);
                //如果有缓存,且需要重新验证,则设置它的IMS信息,为了简便,这里没有验证ETag
                if(cache != null)
                {
                    webRequest.IfModifiedSince = cache.LastModified;
                }
    
                HttpWebResponse response = null;
                Stream stream = null;
                try
                {
                    response = webRequest.GetHttpResponse();
                    //如果服务器资源没有修改,则修改缓存信息后,返回内容
                    if (cache != null && response.StatusCode == HttpStatusCode.NotModified)
                    {
                        cache.UpdateCacheProperty(response);
                        return cache.Html;
                    }
    
                    //服务器资源已经修改,重新获取内容,并放入缓存
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        stream = response.GetResponseStream();
                        TextReader reader = new StreamReader(stream);
    
                        cache = new HtmlLocalCache();
                        cache.SetCacheProperty(response);
                        cache.Html = reader.ReadToEnd();
                        AddHtmlToCache(url, cache);
    
                        return cache.Html;
                    }
    
                    return "";
                }
                finally
                {
                    if(response != null) response.Close();
                    if(stream != null) stream.Dispose();
                }
            }
    
            private static void AddHtmlToCache(string url, HtmlLocalCache cache)
            {
                lock (AddCacheLock)
                {
                    if (!_caches.ContainsKey(url))
                    {
                        _caches.Add(url, cache);
                    }
                }
            }
    
            /// <summary>
            /// 缓存数据
            /// </summary>
            private class HtmlLocalCache
            {
                public String Html;
                public DateTime LastModified;
                public DateTime? ExpiredTime;
                public DateTime HttpDate;
                private Object _updateLock = new Object();
    
                public Boolean NeedRevalidate()
                {
                    if (ExpiredTime == null) return true;
                    if (FromRefresh()) return true;
                    return DateTime.Now > ExpiredTime;
                }
    
                /// <summary>
                /// 看是否是页面刷新
                /// </summary>
                /// <returns></returns>
                private static bool FromRefresh()
                {
                    string requestCacheControl = HttpContext.Current.Request.Headers["Cache-Control"];
                    String pragma = HttpContext.Current.Request.Headers["Pragma"];
                    Boolean isRefresh = (pragma != null &&
                                         pragma.Equals("no-cache", StringComparison.OrdinalIgnoreCase)
                                         || requestCacheControl != null &&
                                         requestCacheControl.Equals("no-cache", StringComparison.OrdinalIgnoreCase));
                                        
                    if (isRefresh) return true;
                    return false;
                }
    
                private void SetCacheControl(string cacheControl)
                {
                    if (String.IsNullOrEmpty(cacheControl)) return;
    
                    if(cacheControl.Contains("max-age"))
                    {
                        Double maxAge = Double.Parse(cacheControl.Substring(cacheControl.IndexOf('=')+1));
                        ExpiredTime = HttpDate.AddSeconds(maxAge);
                    }
                }
    
                public void SetCacheProperty(HttpWebResponse response)
                {
                    LastModified = response.LastModified;
                    HttpDate = Convert.ToDateTime(response.Headers["Date"]);
                    //使用cache-control来控制缓存过期时间,不使用expires
                    SetCacheControl(response.Headers["Cache-Control"]);
                }
    
                public void UpdateCacheProperty(HttpWebResponse response)
                {
                    lock (_updateLock)
                    {
                        SetCacheProperty(response);
                    }
                }
            }
        }
  • 相关阅读:
    Fancybox丰富的弹出层效果
    oracle wm_concat(column)函数的使用
    asp.net下ajax.ajaxMethod使用方法
    sql2008 附加数据库出错解决方法
    关于mysql-5.7.13-winx64服务无法启动的解决方法
    解决懒加载异常
    学生各科成绩,平均分,总分的展示
    docker desktop v20 设置文件路径,windows docker 设置设置路径
    自动化运维工具:jumpserver/jms_all
    linux kill 进程正则表达式
  • 原文地址:https://www.cnblogs.com/hnsongbiao/p/7237850.html
Copyright © 2011-2022 走看看