2012-02-23 35 views
6

有誰知道爲什麼如果我的頁面上有cookie,輸出緩存不起作用!當部署到IIS 6或7,這並不緩存,但是如果我註釋掉它執行3條Response.Cookies線後面asp.net outputcache和cookies

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 

例頁

<%@ 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> 

實施例的代碼。

在VS中運行時,它可以正常工作。

是否有IIS/web.config文件等一些設置,允許輸出緩存,而我設置response.cookies。我知道cookie內容將被緩存,並且它只是緩存的http響應的一部分。

謝謝

Symeon。

+0

你有沒有前夕r找到了解決辦法? – Allov 2012-03-21 13:52:37

+1

我發現同樣的事情是真實的,但沒有遇到任何官方文檔。明確聲明它不起作用。 – JNappi 2012-04-16 16:07:21

+0

@Allov,對於延遲抱歉 - 不,我沒有解決方案。除了擺脫cookie或如果我需要一個cookie,我可以在剛剛設置cookie的頁面上添加腳本標記或0x0圖像。 – 2012-04-17 08:50:57

回答

4

您嘗試緩存此服務器端,並在同一時間,你嘗試設置在客戶端上的cookie - 這不是一起工作。

爲什麼:當你在服務器端設置頁面緩存後面的代碼時,緩存版本的服務沒有運行(發送到客戶端)。這是服務器上的緩存點。不運行任何東西,並按原樣從緩存中提供。

也許你只需要在緩存頭上設置緩存,而不是在服務器上緩存整個頁面。

+1

我正在創建一個頁面在asp.net中有一個cookie。我希望iis緩存這個頁面,而不是在後面運行代碼。我正在使用標準的.net代碼來執行此操作。然而,它看起來像我以任何方式使用response.cookie outputcache指令破壞。這在.net中沒有以任何方式記錄。事實上,有一篇文章說,如果你使用緩存cookie的方式來緩存頁面,我很清楚cookie是http頭文件的一部分,因此將被緩存。我的問題是,如果有一個設置在iis/web.config等,使這個。它在卡西尼運行時效果不錯 – 2012-02-23 11:31:01

+0

@Symeon這不符合邏輯(錯誤)你試圖做什麼。你爲一個用戶設置了一個cookie,那麼下一個沒有設置cookie的用戶呢?在客戶端設置的Cookie - 您已將客戶端緩存與服務器緩存混合在一起。當客戶端不在服務器上時,cookie也保存在緩存上 – Aristos 2012-02-23 11:46:47

+1

訪問該頁面的任何人都將被給予cookie,無論它是否存在。 Cookie只是http頭中的文本。我明白了爲什麼它可能會令人困惑,但我只是認爲必須有一些配置,因爲它沒有聲明它們是互斥的,它在卡西尼中工作正常。看看這個-http://support.microsoft.com/kb/917072聽起來像它應該緩存與cookie,因爲他們提供了一種解決方法來阻止它。 – 2012-02-23 12:06:36

0

我有同樣的問題,我通過設置位置=「ServerAndClient」和它的作品通過測試給出Aristos的場景。如果我只使用Location =「Server」,那麼它不起作用。

+0

在你的情況,只有客戶端(HTTP響應頭緩存)將工作。如果您在響應中設置了Cookie,頁面輸出將不會被緩存在服務器上。 – d4n3 2012-06-06 14:39:46

1

檢查,看看你正在運行的.NET 2.0 SP1,如果您已經申請MS11-100(2012年12月發佈)。

我們遇到過類似的問題,最終接觸到了Microsoft支持。他們證實MS11-100打破輸出緩存,但聲稱這是設計的(由於修補程序中修復了安全漏洞的性質),目前還沒有任何措施可以恢復輸出緩存功能。

一個簡單的測試:如果你發現你已經安裝了補丁,只需卸載該補丁並重新啓動即可。你應該看到輸出緩存開始工作。我認爲任何人都不會因爲安全問題而將其推薦爲生產解決方案,所以只能將其作爲解決問題的手段。我們最終測試了一個更新的框架(你必須去4.0; 3.5只是2.0框架的擴展,而不是獨立的框架),並且在解決所有編譯錯誤後,輸出緩存立即開始工作。

我們還致力於改變我們使用Cookie進行互動,使我們能夠停留在2.0框架的方式(畢竟,它應該是更容易測試,而不是測試整個整個應用我們的cookie處理程序類)。有很多障礙,最後的產品都是「黑客」,所以這是一個不行。

2

這是由不同版本的.NET框架引起的。基本上,一些版本不會使用cookie集緩存頁面。

See this blog posting

+0

歡迎來到Stack Overflow!感謝您發佈您的答案!請務必仔細閱讀[自助推廣常見問題](http://stackoverflow.com/faq#promotion)。另請注意,每次鏈接到您自己的網站/產品時,您都必須*發佈免責聲明。 – 2012-10-05 20:57:00

-1

有可能在某些情況下工作的一種變通方法: 如果cookie不嚴重依賴於網頁代碼,但可以通過一些專門的代碼來計算,您可以設置Cookie在Application_EndRequest 的Application_EndRequest的後處理OutputCache,因此緩存沒有cookie存儲,但是在請求被傳送到客戶端之前添加了設置的cookie頭。

+0

我試過這個方法,收到「響應發送錯誤後無法修改頭文件」。 – WiseGuyEh 2016-03-31 08:56:57

2

在對這個問題進行了一點研究之後,我開始瞭解和解決這個問題。

原因輸出緩存沒有發揮好與cookies

所以輸出緩存將不緩存與cookies響應的原因是,一個cookie可以是用戶特定的(例如身份驗證,分析跟蹤,等等。)。如果一個或多個cookie屬性爲HttpCookie.Shareable = false,則輸出緩存會將響應視爲不可緩存。

包括與緩存的響應

這是它獲得的棘手餅乾。輸出緩存將響應標頭和內容緩存在一起,並且在將它們發送回用戶之前不提供任何鉤子來修改它們。 不過,我寫了下面的自定義輸出緩存提供提供修改緩存響應頭的能力,他們在發送之前返回給用戶(要求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> 

而且可以使用它像這樣插入餅乾:

HeaderModOutputCacheProvider.RequestServedFromCache += RequestServedFromCache; 

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