gpt4 book ai didi

ASP.NET 输出缓存和 Cookie

转载 作者:行者123 更新时间:2023-12-04 03:39:50 25 4
gpt4 key购买 nike

有谁知道为什么如果我的页面上有 cookie,输出缓存不起作用!

示例页面

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="ct.aspx.vb" Inherits="ct" %>
<%@ OutputCache Duration="600" Location="Server" VaryByParam="none" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>Cache test</h1>
<p id="rndout" runat="server"></p>
</div>
</form>
</body>
</html>

后面的示例代码:

Partial Class ct
Inherits System.Web.UI.Page

Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
Dim rc As New Random()
Dim rn As Integer
rn = rc.Next()
rndout.InnerHtml = rn.ToString

Response.Cookies("sym")("hello") = "world"
Response.Cookies("sym").Expires = DateTime.Now.AddDays(370)
Response.Cookies("sym").Domain = Application.Get("cookieurl")

End Sub
End Class

当部署到 iis 6 或 7 时,它不会缓存,但是如果我注释掉 3 Response.Cookies 行,它会缓存。

在 VS 中运行时,两种方式都可以正常工作。

iis/web.config 等中是否有一些设置允许在我设置 response.cookies 时输出缓存。我知道 cookie 内容将被缓存,因为它只是缓存的 http 响应的一部分。

最佳答案

在对这个问题进行了相当多的研究之后,我开始理解并解决了这个问题。

输出缓存无法与 cookie 配合使用的原因

因此,输出缓存不会缓存带有 cookie 的响应的原因是 cookie 可能是用户特定的(例如身份验证、分析跟踪等)。如果一个或多个带有 HttpCookie.Shareable = false 属性的 cookie ,则输出缓存认为响应不可缓存。

包括带有缓存响应的 cookie

这就是它变得棘手的地方。输出缓存将响应 header 和内容缓存在一起,并且在将它们发送回用户之前不提供任何 Hook 来修改它们。
但是,我编写了以下自定义输出缓存提供程序,以提供在将缓存响应的 header 发送回用户之前修改它们的能力(需要 Fasterflect nuget 包):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using System.Web;
using System.Web.Caching;
using Fasterflect;

namespace CustomOutputCache
{
/// <summary>
/// An output cache provider that has ability to modify the http header collection before a cached response is served back to the user.
/// </summary>
public class HeaderModOutputCacheProvider : OutputCacheProvider
{
private static readonly Type OutputCacheEntryType, HttpCachePolicySettingsType;
private static readonly Type[] ParameterTypes;

public static event EventHandler<CachedRequestEventArgs> RequestServedFromCache;

static HeaderModOutputCacheProvider()
{
var systemWeb = typeof(HttpContext).Assembly;
OutputCacheEntryType = systemWeb.GetType("System.Web.Caching.OutputCacheEntry");
HttpCachePolicySettingsType = systemWeb.GetType("System.Web.HttpCachePolicySettings");
ParameterTypes = new[]{
typeof(Guid),
HttpCachePolicySettingsType,
typeof(string),
typeof(string) ,
typeof(string[]),
typeof(int),
typeof(string),
typeof(List<HeaderElement>),
typeof(List<ResponseElement>)
};
}

private readonly ObjectCache _objectCache;

public HeaderModOutputCacheProvider()
{
_objectCache = new MemoryCache("output-cache");
}

#region OutputCacheProvider implementation

public override object Get(string key)
{
var cachedValue = _objectCache.Get(key);

if (cachedValue == null)
return null;

if (cachedValue.GetType() != OutputCacheEntryType)
return cachedValue;

var cloned = CloneOutputCacheEntry(cachedValue);

if (RequestServedFromCache != null)
{
var args = new CachedRequestEventArgs(cloned.HeaderElements);
RequestServedFromCache(this, args);
}

return cloned;
}

public override object Add(string key, object entry, DateTime utcExpiry)
{
_objectCache.Set(key, entry, new CacheItemPolicy { AbsoluteExpiration = utcExpiry });
return entry;
}

public override void Set(string key, object entry, DateTime utcExpiry)
{
_objectCache.Set(key, entry, new CacheItemPolicy { AbsoluteExpiration = utcExpiry });
}

public override void Remove(string key)
{
_objectCache.Remove(key);
}

#endregion

private IOutputCacheEntry CloneOutputCacheEntry(object toClone)
{
var parameterValues = new[]
{
toClone.GetFieldValue("_cachedVaryId", Flags.InstancePrivate),
toClone.GetFieldValue("_settings", Flags.InstancePrivate),
toClone.GetFieldValue("_kernelCacheUrl", Flags.InstancePrivate),
toClone.GetFieldValue("_dependenciesKey", Flags.InstancePrivate),
toClone.GetFieldValue("_dependencies", Flags.InstancePrivate),
toClone.GetFieldValue("_statusCode", Flags.InstancePrivate),
toClone.GetFieldValue("_statusDescription", Flags.InstancePrivate),
CloneHeaders((List<HeaderElement>)toClone.GetFieldValue("_headerElements", Flags.InstancePrivate)),
toClone.GetFieldValue("_responseElements", Flags.InstancePrivate)
};

return (IOutputCacheEntry)OutputCacheEntryType.CreateInstance(
parameterTypes: ParameterTypes,
parameters: parameterValues
);
}

private List<HeaderElement> CloneHeaders(List<HeaderElement> toClone)
{
return new List<HeaderElement>(toClone);
}
}

public class CachedRequestEventArgs : EventArgs
{
public CachedRequestEventArgs(List<HeaderElement> headers)
{
Headers = headers;
}
public List<HeaderElement> Headers { get; private set; }

public void AddCookies(HttpCookieCollection cookies)
{
foreach (var cookie in cookies.AllKeys.Select(c => cookies[c]))
{
//more reflection unpleasantness :(
var header = cookie.CallMethod("GetSetCookieHeader", Flags.InstanceAnyVisibility, HttpContext.Current);
Headers.Add(new HeaderElement((string)header.GetPropertyValue("Name"), (string)header.GetPropertyValue("Value")));
}
}
}
}

你会像这样连接它:
<system.web>
<caching>
<outputCache defaultProvider="HeaderModOutputCacheProvider">
<providers>
<add name="HeaderModOutputCacheProvider" type="CustomOutputCache.HeaderModOutputCacheProvider"/>
</providers>
</outputCache>
</caching>
</system.web>

并且可以像这样使用它来插入cookie:
HeaderModOutputCacheProvider.RequestServedFromCache += RequestServedFromCache;

HeaderModOutputCacheProvider.RequestServedFromCache += (sender, e) =>
{
e.AddCookies(new HttpCookieCollection
{
new HttpCookie("key", "value")
});
};

关于ASP.NET 输出缓存和 Cookie,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9411180/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com