欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

CreateOutputCachedItemKey 缓存key的创建

程序员文章站 2024-03-06 14:17:08
有关outputcache的相关资料大家可以查看 outputcacheprovider outputcache的一点点认识 ,我们还是复习一下outputcache内容,...
有关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过来的数据有关。