ASP.NET输出缓存和Cookie

ASP.NET输出缓存和Cookie,asp.net,cookies,outputcache,Asp.net,Cookies,Outputcache,有人知道为什么如果我的页面上有cookies,输出缓存不工作 示例页 <%@ 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

有人知道为什么如果我的页面上有cookies,输出缓存不工作

示例页

<%@ 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>
当部署到iis 6或7时,这不会缓存,但是如果我注释掉3响应,它会缓存

当在VS中运行时,两种方式都很好


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

您尝试在服务器端缓存它,同时尝试在客户端设置cookie-这不起作用

原因:当您在服务器端的缓存上设置页面时,在提供缓存版本(发送到客户端)时,隐藏的代码不会运行。这就是在服务器上缓存的要点。不运行任何内容并按原样从缓存中提供


也许您只需要在页眉上设置缓存,而不在服务器上缓存整个页面。

我也遇到了同样的问题,我通过设置Location=“ServerAndClient”测试了Aristos给出的场景,它可以工作。如果我只使用Location=“Server”,那么它就不起作用了

检查您是否正在运行.NET 2.0 SP1以及是否应用了MS11-100(2012年12月发布)

我们也遇到了类似的问题,最终寻求了微软的支持。他们确认MS11-100破坏了输出缓存,但声称这是出于设计(由于修补程序中修复的安全漏洞的性质),目前没有采取任何措施来恢复输出缓存功能

一个简单的测试:如果发现安装了补丁,只需卸载该补丁并重新启动。您应该看到输出缓存开始工作。由于安全问题,我认为没有人会建议将其作为生产解决方案,因此仅将其用作隔离问题的一种方法

我们最终测试了一个较新的框架(您必须转到4.0;3.5只是2.0框架的扩展,而不是独立框架本身),并且在解决了所有编译错误后,输出缓存立即开始工作


我们还致力于改变与cookie交互的方式,以便我们能够保持在2.0框架上(毕竟,测试cookie处理程序类应该比测试整个应用程序更容易)。有很多障碍,最终产品散发着“黑客”的味道,所以这是不可能的。

这是由不同版本的.NET framework造成的。基本上,某些版本永远不会缓存设置了cookie的页面


.

在某些情况下,有一种变通方法可能有效: 如果cookie在很大程度上不依赖于页面代码,但可以使用一些独立代码进行计算,则可以在应用程序中设置cookie
应用程序的EndRequest在OutputCache之后处理,因此缓存存储时没有cookie,但在请求发送到客户端之前添加了set cookie头。

在对这个问题进行了大量研究之后,我开始理解并解决这个问题

输出缓存不能很好地处理cookie的原因

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

包括具有缓存响应的cookie

这就是问题的症结所在。输出缓存将响应头和内容缓存在一起,并且在将它们发送回用户之前不提供任何钩子来修改它们。 但是,我编写了以下自定义输出缓存提供程序,以提供在将缓存响应的头发送回用户之前修改它们的能力(需要FasterflectNuGet包):


我正在asp.net中创建一个包含cookie的页面。我希望iis缓存此页,而不是运行代码。我正在使用标准的.net代码来实现这一点。但是,如果我以任何方式使用response.cookie,outputcache指令就会被破坏。在.net中没有以任何方式记录这一点。事实上,有一篇文章说,记住,如果你用cookies缓存页面,cookies也会被缓存。我很清楚cookie是http头的一部分,因此将被缓存。我的问题是iis/web.config等中是否有启用此功能的设置。磨合时工作正常cassini@Symeon这不是你试图做的合乎逻辑的事情。您将cookie设置为一个用户,那么下一个没有cookie设置的用户呢?客户端上设置的cookie-您将客户端缓存与服务器缓存混淆。当cookie位于客户端而不是服务器上时,cookie也会保留在缓存中。任何访问页面的人都会得到一个cookie,不管它是否存在。cookie只是http头中的文本。我可以理解为什么它可能会让人困惑,但我只是认为一定有一些配置,因为它没有说明它们在哪里是相互排斥的,而且在卡西尼号上也可以。看看这个-听起来它应该和cookie一起缓存,因为他们提供了一个解决方案来阻止它。你找到解决方案了吗?我发现同样的事情是真的,但没有遇到任何官方文档。明确说明它不起作用。@Allov,很抱歉耽搁了-不,我没有解决办法。除了去掉cookie或者如果我需要cookie,我可以在页面上添加一个脚本标记或0x0图像来设置cookie。虽然已经晚了几年,但这家伙还是找到了解决办法。目前还不知道这有多危险。在您的情况下,只有客户端(HTTP响应头缓存)可以工作。如果您在响应中设置cookies,页面输出将不会缓存在服务器上。欢迎使用堆栈溢出!谢谢你的回复!请务必仔细阅读本手册。还请注意,要求您每天发布免责声明
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>
HeaderModOutputCacheProvider.RequestServedFromCache += RequestServedFromCache;

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