您的位置:首页 > 理论基础 > 计算机网络

一个具有缓存数据功能的HttpWebRequest工具类

2017-07-26 09:30 309 查看
背景:一个公共站点中的数据,供其它子站点共享,为了提高性能,简单实现了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);
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐