2012-02-23 32 views
6

Có ai biết tại sao nếu có cookie trên trang của tôi, bộ đệm đầu ra không hoạt động!asp.net outputcache và cookie

trang Ví dụ

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

Ví dụ mã sau

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 

khi triển khai để IIS 6 hoặc 7 này không cache, tuy nhiên nếu tôi nhận xét ra các Response.Cookies dòng 3 nó.

Khi chạy hết trong VS, nó hoạt động tốt theo cả hai cách.

Có một số cài đặt trong iis/web.config vv để cho phép outputcache trong khi tôi đặt response.cookies. Tôi hiểu rằng nội dung cookie sẽ được lưu trong bộ nhớ cache cũng như nó chỉ là một phần của phản hồi http được lưu trong bộ nhớ cache.

Cảm ơn

Symeon.

+0

bạn có eve r tìm thấy một giải pháp? – Allov

+1

Tôi thấy điều tương tự là đúng nhưng chưa gặp phải bất kỳ tài liệu chính thức nào. nói rõ rằng nó không hoạt động. – JNappi

+0

@Allov, xin lỗi vì sự chậm trễ - không có tôi không có giải pháp. Ngoại trừ việc loại bỏ cookie hoặc nếu tôi cần cookie, tôi có thể thêm thẻ tập lệnh hoặc hình ảnh 0x0 trên trang chỉ đặt cookie. –

Trả lời

4

Bạn cố gắng lưu bộ nhớ cache này ở phía máy chủ và đồng thời bạn cố đặt cookie trên máy khách - điều này không hoạt động cùng nhau.

Lý do: Khi bạn đặt trang trên bộ nhớ cache ở phía máy chủ, mã phía sau không chạy khi phiên bản được lưu trong bộ nhớ cache được phân phát (gửi tới máy khách). Đây là điểm đệm trong máy chủ. Để không chạy bất cứ điều gì và cung cấp cho nó từ bộ nhớ cache như nó được.

Có thể bạn chỉ cần đặt bộ nhớ cache trên tiêu đề và không lưu toàn bộ trang trên máy chủ.

+1

Tôi đang tạo một trang trong asp.net có cookie. Tôi muốn iis để cache trang này và không chạy mã phía sau. Tôi đang sử dụng mã .net chuẩn để thực hiện việc này. Tuy nhiên nó trông giống như nếu tôi sử dụng response.cookie trong bất kỳ cách nào chỉ thị outputcache bị phá vỡ. Đây không phải là tài liệu trong bất kỳ cách nào trong .net. trong thực tế, có một bài viết nói rằng hãy nhớ nếu bạn cache một trang có cookie thì cookie cũng được lưu trong bộ nhớ cache. Tôi biết rõ rằng cookie là một phần của tiêu đề http và do đó sẽ được lưu vào bộ nhớ cache. câu hỏi của tôi là nếu có một thiết lập trong iis/web.config vv cho phép điều này. Nó hoạt động ok khi chạy trong cassini –

+0

@Symeon điều này là không hợp lý (buggy) những gì bạn cố gắng làm. Bạn đặt cookie cho một người dùng, điều gì về người dùng tiếp theo không có cookie? Cookie được đặt trên máy khách - bạn đã kết hợp bộ nhớ cache của máy khách với bộ đệm máy chủ. Cookie cũng được lưu trên bộ nhớ cache khi chúng ở phía máy khách chứ không phải trên máy chủ – Aristos

+1

Bất kỳ ai truy cập trang sẽ được cung cấp cookie, cho dù cookie đó có tồn tại hay không. Cookie chỉ là văn bản trong tiêu đề http. Tôi có thể thấy lý do tại sao nó có thể gây nhầm lẫn, nhưng tôi chỉ nghĩ rằng phải có một số cấu hình như không có nơi nào nó nhà nước họ là loại trừ lẫn nhau, và nó hoạt động ok trong cassini.xem xét này -http: //support.microsoft.com/kb/917072 âm thanh như nó NÊN được bộ nhớ đệm với cookie khi họ cung cấp cho một workaround để ngăn chặn nó. –

0

Tôi đã gặp vấn đề tương tự và tôi đã thử nghiệm kịch bản do Aristos đưa ra bằng cách đặt Location = "ServerAndClient" và nó hoạt động. Nếu tôi chỉ sử dụng Location = "Server" thì nó không hoạt động.

+0

Trong trường hợp của bạn, chỉ ứng dụng khách (bộ nhớ đệm tiêu đề phản hồi HTTP) mới hoạt động. Đầu ra trang sẽ không được lưu trữ trên máy chủ nếu bạn đặt cookie trong phản hồi của mình. – d4n3

1

Kiểm tra xem bạn có đang chạy .NET 2.0 SP1 không và nếu bạn đã áp dụng MS11-100 (phát hành tháng 12 năm 2012).

Chúng tôi đã gặp phải sự cố tương tự và đã kết thúc với Microsoft Support. Họ xác nhận MS11-100 phá vỡ bộ nhớ đệm đầu ra nhưng tuyên bố nó là do thiết kế (do tính chất của lỗ hổng bảo mật cố định trong bản vá) và hiện tại không có gì được thực hiện để khôi phục chức năng bộ đệm đầu ra.

Một thử nghiệm đơn giản: nếu bạn thấy mình đã cài đặt bản vá, chỉ cần gỡ cài đặt bản vá đó và khởi động lại. Bạn sẽ thấy rằng bộ nhớ đệm đầu ra bắt đầu hoạt động. Tôi không nghĩ rằng bất cứ ai sẽ đề nghị này như là một giải pháp sản xuất do các tác động an ninh vì vậy chỉ sử dụng điều này như một phương tiện để cô lập vấn đề.

Chúng tôi đã thử nghiệm một khung công tác mới hơn (bạn phải truy cập 4.0; 3.5 chỉ là một phần mở rộng của khung 2.0 và không phải là một khung độc lập) và sau khi giải quyết tất cả các lỗi biên dịch, bộ nhớ đệm đầu ra bắt đầu hoạt động ngay lập tức .

Chúng tôi cũng đã làm việc để thay đổi cách chúng ta tương tác với cookie để chúng tôi có thể ở trên khung 2.0 (sau khi tất cả, sẽ dễ dàng hơn để kiểm tra các lớp trình xử lý cookie của chúng tôi thay vì kiểm tra toàn bộ ứng dụng). Có một số trở ngại và sản phẩm cuối cùng reeked của "hack" do đó là một không-đi.

2

Đó là do các phiên bản .NET framework khác nhau. Về cơ bản, một số phiên bản sẽ không bao giờ cache trang với tập hợp cookie.

See this blog posting.

+0

Chào mừng bạn đến với Stack Overflow! Cảm ơn bạn đã đăng câu trả lời! Vui lòng đảm bảo đọc kỹ [FAQ on Self-Promotion] (http://stackoverflow.com/faq#promotion). Cũng lưu ý rằng nó là * bắt buộc * mà bạn đăng tuyên bố từ chối trách nhiệm mỗi khi bạn liên kết đến trang web/sản phẩm của riêng bạn. –

-1

Có một workaround mà có thể làm việc trong một số kịch bản: Nếu cookie không phụ thuộc rất nhiều vào các mã trang nhưng có thể được tính toán với một số mã độc, bạn có thể thiết lập các cookie trong Application_EndRequest Các Application_EndRequest được xử lý sau OutputCache và do đó bộ nhớ cache được lưu trữ không có cookie nhưng sau đó tiêu đề cookie được đặt sẽ được thêm trước khi yêu cầu được gửi tới máy khách.

+0

Tôi đã thử phương pháp này và nhận được một "không thể sửa đổi tiêu đề sau khi phản ứng đã được gửi lỗi". – WiseGuyEh

2

Sau khi thực hiện một chút công bằng về nghiên cứu này, tôi đã hiểu và giải quyết vấn đề.

Sản lượng bộ nhớ cache lý do không chơi đẹp với cookie

Vì vậy, lý do bộ nhớ cache đầu ra sẽ không cache một phản ứng với cookie là một cookie có thể được sử dụng cụ thể (ví dụ xác thực, theo dõi phân tích, v.v.) Nếu một hoặc nhiều cookie có thuộc tính HttpCookie.Shareable = false thì bộ nhớ cache đầu ra sẽ xem xét phản hồi không thể thu thập được.

Bao gồm cookie với một phản ứng cache

Đây là nơi mà nó có được của khéo léo. Bộ nhớ cache đầu ra lưu trữ các tiêu đề phản hồi và nội dung với nhau và không cung cấp bất kỳ móc nối nào để sửa đổi chúng trước khi gửi lại cho người dùng. Tuy nhiên, tôi đã viết nhà cung cấp bộ nhớ cache đầu ra tùy chỉnh sau để cung cấp khả năng sửa đổi tiêu đề một phản ứng cache trước khi chúng được gửi trở lại cho người sử dụng (đòi hỏi sự Fasterflect NuGet gói):

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"))); 
      } 
     } 
    } 
} 

Bạn sẽ dây nó lên như thế này:

<system.web> 
    <caching> 
     <outputCache defaultProvider="HeaderModOutputCacheProvider"> 
     <providers> 
      <add name="HeaderModOutputCacheProvider" type="CustomOutputCache.HeaderModOutputCacheProvider"/> 
     </providers> 
     </outputCache> 
    </caching> 
    </system.web> 

Và có thể sử dụng nó như thế này để chèn các tập tin cookie:

HeaderModOutputCacheProvider.RequestServedFromCache += RequestServedFromCache; 

HeaderModOutputCacheProvider.RequestServedFromCache += (sender, e) => 
{ 
    e.AddCookies(new HttpCookieCollection 
    { 
     new HttpCookie("key", "value") 
    }); 
}; 
Các vấn đề liên quan