CreateOutputCachedItemKey 缓存key的创建

 更新时间:2021年9月22日 10:18  点击:1998
有关OutputCache的相关资料大家可以查看 OutputCacheProvider OutputCache的一点点认识 ,我们还是复习一下OutputCache内容,OutputCache 的处理是在OutputCacheModule类中注册ResolveRequestCache、UpdateRequestCache这2个方法,一个 用于获取一个用于设置缓存。缓存内容分为两部分,一部分为缓存策略CachedVary,一部分为缓存数据CachedRawResponse,一个页面 缓存策略只有一个CachedVary,但是它却可以有多个缓存内容CachedRawResponse。缓存内容的获取和设置主要是依赖于HttpResponse的GetSnapshot() UseSnapshot(HttpRawResponse rawResponse, bool sendBody)方法。一般我们的缓 存都是要占用存储空间的尽量减少缓存内容的副本是非常重要的,那么我们现在就来看看缓存key是如何创建的,key的创建取决于 CreateOutputCachedItemKey方法。CreateOutputCachedItemKey方法的内容还是比较复杂的,现在让我们一 起来看看它的具体实现吧。

CreateOutputCachedItemKey方法又是如何调用的了,创建缓存策略key的代码:this.CreateOutputCachedItemKey(context, null);创建缓存key的代码:this.CreateOutputCachedItemKey(context, cachedVary)区别就在于参数CachedVary 的值一个为null,一个是真正的CachedVary 实例。我这里的代码是通过Reflector.exe反编译得到,感觉和真实的代码有点差别,不过逻辑上是一样的。
我还是以一个实际的例子来变解析边说明,我这里是用asp.net mvc建立的一个demo。请求url:http://localhost:7503/Home/index 那么path就应该是:Home/index
首先我们的可以需要区分我们的请求是Get还是Post,Post以a1打头,否则已a2打头,紧接着追加当前的Path:
复制代码 代码如下:

if (verb == HttpVerb.POST)
{
builder = new StringBuilder("a1", path.Length + "a1".Length);
}
else
{
builder = new StringBuilder("a2", path.Length + "a2".Length);
}
builder.Append(CultureInfo.InvariantCulture.TextInfo.ToLower(path));

到这个时候我们的缓存策略key及确定的,我这里的策略key为:a2/home/index
如果我们的cachedVary不为null则继续执行:
复制代码 代码如下:

for (int i = 0; i <= 2; i++)
{
int num;
string[] array = null;
NameValueCollection serverVarsWithoutDemand = null;
bool flag = false;
switch (i)
{
case 0:
builder.Append("H");
array = cachedVary._headers;
if (array != null)
{
serverVarsWithoutDemand = request.GetServerVarsWithoutDemand();
}
break;
case 1:
builder.Append("Q");
array = cachedVary._params;
if (request.HasQueryString && ((array != null) || cachedVary._varyByAllParams))
{
serverVarsWithoutDemand = request.QueryString;
flag = cachedVary._varyByAllParams;
}
break;
default:
builder.Append("F");
if (verb == HttpVerb.POST)
{
array = cachedVary._params;
if (request.HasForm && ((array != null) || cachedVary._varyByAllParams))
{
serverVarsWithoutDemand = request.Form;
flag = cachedVary._varyByAllParams;
}
}
break;
}
if (flag && (serverVarsWithoutDemand.Count > 0))
{
array = serverVarsWithoutDemand.AllKeys;
num = array.Length - 1;
while (num >= 0)
{
if (array[num] != null)
{
array[num] = CultureInfo.InvariantCulture.TextInfo.ToLower(array[num]);
}
num--;
}
Array.Sort(array, InvariantComparer.Default);
}
if (array != null)
{
num = 0;
int length = array.Length;
while (num < length)
{
string str = array[num];
if (serverVarsWithoutDemand == null)
{
varyByCustomString = "+n+";
}
else
{
varyByCustomString = serverVarsWithoutDemand[str];
if (varyByCustomString == null)
{
varyByCustomString = "+n+";
}
}
builder.Append("N");
builder.Append(str);
builder.Append("V");
builder.Append(varyByCustomString);
num++;
}
}
}

这段代码说白了就是给key值追加HQF3个字符,这个循环首先处理服务器的数据,
array = cachedVary._headers;
serverVarsWithoutDemand = request.GetServerVarsWithoutDemand();
其次是处理QueryString数据:
array = cachedVary._params;
serverVarsWithoutDemand = request.QueryString;
最后处理Form数据
array = cachedVary._params;
serverVarsWithoutDemand = request.Form;
serverVarsWithoutDemand是NameValueCollection 类型的数据,这里循环serverVarsWithoutDemand里面的每个key,每个key对应的追加字符串为N+key+V+value,如果value是null则从新赋值为“+n+”,可以看见不同的请求这里的key及有所不同了。在QueryString和Form时这里的serverVarsWithoutDemand的取值与
cachedVary._varyByAllParams有关,cachedVary的创建是在OutputCacheModule 的OnLeave方法中:
vary = new CachedVary(varyByContentEncodings, varyByHeaders, varyByParams, varyByAllParams, currentSettings.VaryByCustom);
varyByAllParams的取值如下:
复制代码 代码如下:

bool varyByAllParams = false;
if (varyByParams != null)
{
varyByAllParams = (varyByParams.Length == 1) && (varyByParams[0] == "*");
}

可见varyByAllParams基本都是false,只有varyByParams有且紧有一个元素并且为*时,varyByAllParams才为true,varyByAllParams为false时这里的serverVarsWithoutDemand取值为GetServerVarsWithoutDemand方法,与我们的QueryString、Form3没什么关系。GetServerVarsWithoutDemand()方法大家可能都不怎么熟悉,我们来看看它的定义:
复制代码 代码如下:

internal NameValueCollection GetServerVarsWithoutDemand()
{
return this.GetServerVars();
}

对这个方法不了解不要紧,我们有一个ServerVariables(获取 Web 服务器变量的集合)属性和他相似:
复制代码 代码如下:

public NameValueCollection ServerVariables
{
get
{
if (HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Low))
{
return this.GetServerVars();
}
return this.GetServerVarsWithDemand();
}
}

其中GetServerVarsWithDemand方法也是调用GetServerVars方法。现在serverVarsWithoutDemand的数据我们也搞清楚了。
builder.Append("C"); 接下来在追加字符C
接下来我们该处理缓存_varyByCustom的配置了
复制代码 代码如下:

if (cachedVary._varyByCustom != null)
{
builder.Append("N");
builder.Append(cachedVary._varyByCustom);
builder.Append("V");
try
{
varyByCustomString = context.ApplicationInstance.GetVaryByCustomString(context, cachedVary._varyByCustom);
if (varyByCustomString == null)
{
varyByCustomString = "+n+";
}
}
catch (Exception exception)
{
varyByCustomString = "+e+";
HttpApplicationFactory.RaiseError(exception);
}
builder.Append(varyByCustomString);
}

这个方法很好明白,如果_varyByCustom不为null那么我们就追加N+key+V+value格式的字符。其中key就是_varyByCustom字符串,value是调用context.ApplicationInstance.GetVaryByCustomString(context, cachedVary._varyByCustom)得到的value,如果value值为null,则设置为“+n+” builder.Append("D");
复制代码 代码如下:

if (((verb == HttpVerb.POST) && cachedVary._varyByAllParams) && (request.Form.Count == 0))
{
int contentLength = request.ContentLength;
if ((contentLength > 0x3a98) || (contentLength < 0))
{
return null;
}
if (contentLength > 0)
{
byte[] asByteArray = ((HttpInputStream) request.InputStream).GetAsByteArray();
if (asByteArray == null)
{
return null;
}
varyByCustomString = Convert.ToBase64String(MachineKeySection.HashData(asByteArray, null, 0, asByteArray.Length));
builder.Append(varyByCustomString);
}
}

这段代码主要是给key追加一个字符D,然后在处理Post的请求(非表单request.Form.Count == 0)把请求的内容(字节)转化为字符追加到key中,一般的http很少会发生此情况,典型的是HttpWebRequest发生的Post请求会触发。
复制代码 代码如下:

builder.Append("E");
string[] strArray2 = cachedVary._contentEncodings;
if (strArray2 != null)
{
string httpHeaderContentEncoding = context.Response.GetHttpHeaderContentEncoding();
if (httpHeaderContentEncoding != null)
{
for (int j = 0; j < strArray2.Length; j++)
{
if (strArray2[j] == httpHeaderContentEncoding)
{
builder.Append(httpHeaderContentEncoding);
break;
}
}
}
}

这段代码首先给key追加一个字符E,然后最佳ContentEncoding,ContentEncoding的取值为 context.Response.GetHttpHeaderContentEncoding()并且在缓存策略中的 _contentEncodings存在才追加。
到现在为止我们的CreateOutputCachedItemKey方法讲完了,缓存策略的key没什么说的,与Http请求方式Get和Post、Request的Path属性有关。但是缓存数据的key有关对象:
(1)与我们的_headers有关,即配置中的 VaryByHeader属性有关,VaryByHeader取值不同,key则不同
(2)与_varyByAllParams有关,当它为true时,实际上就是与 request.QueryString有关,如果此请求是Post则还与request.Form有关;_varyByAllParams默认为 false,为true的情况也很单一 varyByAllParams = (varyByParams.Length == 1) && (varyByParams[0] == "*")
(3)与_varyByCustom有关,它会把 context.ApplicationInstance.GetVaryByCustomString(context, cachedVary._varyByCustom)方法返回值追加到key中,
(4)与_contentEncodings有关,如果 context.Response.GetHttpHeaderContentEncoding()返回的值在_contentEncodings中则追加其返回值。
注意:如果此Http处理是一个Post并且request.Form.Count ==0&& _varyByAllParams为rue的时候海域我们post过来的数据有关。
[!--infotagslink--]

相关文章

  • JavaScript动态创建div属性和样式示例代码

    1.创建div元素: Javascript代码 复制代码 代码如下: <scripttypescripttype="text/javascript"> functioncreateElement(){ varcreateDiv=document.createElement("div"); createDiv.innerHTML="Testcreateadiveleme...2013-10-13
  • JS创建Tag标签的方法详解

    这篇文章主要介绍了JS创建Tag标签的方法,结合具体实例形式分析了javascript动态操作页面HTML元素实现tag标签功能的步骤与相关操作技巧,需要的朋友可以参考下...2017-06-15
  • 什么是cookie?js手动创建和存储cookie

    什么是cookie? cookie 是存储于访问者的计算机中的变量。每当同一台计算机通过浏览器请求某个页面时,就会发送这个 cookie。你可以使用 JavaScript 来创建和取回 cookie 的值。 有关cookie的例子: 名字 cookie 当访...2014-05-31
  • PS如何创建变形文字 ps给文字变形的方法

    PS怎么创建变形文字?ps中想要给输入的文字变形,该怎么调整文字的显示形态呢?下面我们就来看看ps给文字变形的方法,需要的朋友可以参考下 我们在图层上输入文字后,可以...2017-07-06
  • idea 无法创建Scala class 选项的原因分析及解决办法汇总

    这篇文章主要介绍了idea 无法创建Scala class 选项的解决办法汇总,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-09-02
  • php创建无限级树型菜单

    写递归函数,可考虑缓存,定义一些静态变量来存上一次运行的结果,多程序运行效率很有帮助.。 大概步骤如下: step1:到数据库取数据,放到一个数组, step2:把数据转化为一个树型状的数组, step3:把这个树型状的数组转为html代码。...2015-11-08
  • Drupal模块开发之创建自己的钩子

    Drupal可以让第三方模块创建自己的钩子。在通常的实践中,有两种类型的钩子你可能想要创建,一种是内容修改类的钩子,一种是拦截类的钩子。 Drupal的钩子系统允许和模...2016-11-25
  • C#创建Windows服务的实现方法

    这篇文章主要介绍了C#创建Windows服务的实现方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
  • javascript创建对象的几种模式介绍

    下面小编就为大家带来一篇javascript创建对象的几种模式介绍。小编觉得挺不错的,现在分享给大家,也给大家做个参考...2016-05-09
  • C#对Word文档的创建、插入表格、设置样式等操作实例

    今天小编就为大家分享一篇C#对Word文档的创建、插入表格、设置样式等操作实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-06-25
  • C#动态创建button的方法

    这篇文章主要介绍了C#动态创建button的方法,涉及C#按钮属性动态设置的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • 详解js创建对象的几种方式和对象方法

    这篇文章主要介绍了详解js创建对象的几种方式和对象方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-01
  • 在java中使用SPI创建可扩展的应用程序操作

    这篇文章主要介绍了在java中使用SPI创建可扩展的应用程序操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-14
  • 浅析在javascript中创建对象的各种模式

    下面小编就为大家带来一篇浅析在javascript中创建对象的各种模式。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-05-09
  • C#创建、部署、调用WebService图文实例详解

    本文主要用详细的图文给大家介绍C#创建、部署、调用WebService的全部过程以及中间需要避免的问题。...2020-06-25
  • JS动态创建元素的两种方法

    这篇文章主要为大家详细介绍了JS动态创建元素的两种方法,字符串拼接形式,或是使用Document、Element对象自带的一些函数 ,需要的朋友可以参考下...2016-04-22
  • 动态创建按钮的JavaScript代码

    本文给大家分享一段JS实例代码介绍动态创建按钮的方法,需要的朋友参考下本文...2016-02-01
  • Illustrator创建繁复之美的曼陀罗图案绘制教程

    今天小编在这里就来给Illustrator的这一款软件的使用者们来说一说创建繁复之美的曼陀罗图案的绘制教程,各位想知道具体信息的使用者们,那么下面就快来跟着小编一起看一...2016-09-14
  • php WEB上创建网站

    我们用php来控制iis并且,在WEB上创建网站,管理删除等功能哦。 <? # PHP控制站点程序 # # 编写人:韩湘子 # # 邮箱:hanxiangzi@gmail.com # # MSN:hanx...2016-11-25
  • MySQL创建数据库的两种方法

    这篇文章主要为大家详细介绍了MySQL创建数据库的两种方法,感兴趣的小伙伴们可以参考一下...2016-06-12