一个具有缓存数据功能的HttpWebRequest工具类
2017-07-26 09:30
309 查看
背景:一个公共站点中的数据,供其它子站点共享,为了提高性能,简单实现了Http 1.1的缓存功能
特点:可以缓存Html数据到内存中;缓存具有过期时间;缓存过期后,通过再确认的方式来决定是否更新缓存;浏览器刷新后,无论缓存是否过期都会强制再验证;
未实现的包括:不能通过no-store来强制清空缓存,缓存再确认时没有验证Etag
特点:可以缓存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); } } } }
相关文章推荐
- 一个具有缓存数据功能的HttpWebRequest工具类
- 在一个程序中需要用到全局变量(在多个class之间共享数据),请问如何定义具有这种功能的变量?或者是否有其他的方法解决多个class之间的数据共享(尽量简单实现)。 首先应该明确 Java中没有全局变
- CeleFusion – 具有数据中继/变换功能的 HTTP 代理
- iOS开发:一个高仿美团的团购ipad客户端的设计和实现(功能:根据拼音进行检索并展示数据,离线缓存团购数据,浏览记录与收藏记录的批量删除等)
- 用servlet实现一个注册功能 ,后台获取数据
- 一个具有对象计数功能的基类
- AngularJS基于创建一个完整的mvc模板,($http访问数据)
- Windows Azure上取得更具有竞争力AWS,推出新的移动功能,网页缩放,数据同步等
- 基于yaf框架和uploadify插件,做的一个导入excel文件,查看并保存数据的功能
- 算法与数据机构学习_第一章.栈和队列_1.设计一个有返回栈中最小元素功能的栈
- 基于yaf框架和uploadify插件,做的一个导入excel文件,查看并保存数据的功能
- 手把手教你编写一个具有基本功能的shell(已开源)
- 这是一个定时脚本,主要功能是遍历该文件夹下的所有文件并存储到数组,对数据中的文件进行操作,一个一个移动到指定的目录下,并删除原有文件
- 用jxl将Excel中的数据导入功能的一个问题
- 手把手教你编写一个具有基本功能的shell(已开源)
- 一个简单的JavaScript数据缓存系统实现代码
- jQuery在去除缓存数据的一个失误
- 一个通用的JSP分页类,具有显示多组页码功能(JAVABEAN)
- 实现一个具有百度文库文档转换功能的工具类