2012-02-09 36 views
11

Tôi có một phương pháp hành động mà tôi muốn bộ nhớ cache:OutputCache đang gửi sai tiêu đề Vary khi cuộc gọi lượt truy cập bộ nhớ cache

[OutputCache(Duration=60*5, Location=OutputCacheLocation.Any, VaryByCustom="index")] 
public ActionResult Index() 
{ 
    return View(); 
} 

Với phương pháp này:

public override string GetVaryByCustomString(HttpContext context, string custom) 
{ 
    context.Response.Cache.SetOmitVaryStar(true); 
    context.Response.Cache.VaryByHeaders["Cookie"] = true; 

    if (User.Identity.IsAuthenticated) 
    { 
     Debug.Print("Authenticated"); 
     context.Response.Cache.SetNoServerCaching(); 
     context.Response.Cache.SetCacheability(HttpCacheability.Private); 
     return null; 
    } 
    else 
    { 
     Debug.Print("Non authenticated"); 
     return custom; 
    } 
} 

Ý tưởng là để keep a cached version of the page for non-authenticated users, but avoid caching for authenticated ones.

Tôi nghĩ rằng nó sẽ luôn trả về tiêu đề HTTP Vary:Cookie, nhưng không phải. Làm một thử nghiệm với Fiddler và phát hành hai lần cùng một yêu cầu, trong HTTP đầu tiên gọi nó đi tốt:

HTTP/1.1 200 OK 
Cache-Control: public, max-age=300 
Content-Type: text/html; charset=utf-8 
Expires: Thu, 09 Feb 2012 10:53:36 GMT 
Last-Modified: Thu, 09 Feb 2012 10:48:36 GMT 
Vary: Cookie 
Server: Microsoft-IIS/7.5 
X-AspNetMvc-Version: 3.0 
X-AspNet-Version: 4.0.30319 
X-Powered-By: ASP.NET 
Date: Thu, 09 Feb 2012 10:48:37 GMT 
Content-Length: 441 

Nhưng trong một giây, nó ghi đè header:

HTTP/1.1 200 OK 
Cache-Control: public, max-age=297 
Content-Type: text/html; charset=utf-8 
Expires: Thu, 09 Feb 2012 10:53:36 GMT 
Last-Modified: Thu, 09 Feb 2012 10:48:36 GMT 
Vary: * 
Server: Microsoft-IIS/7.5 
X-AspNetMvc-Version: 3.0 
X-AspNet-Version: 4.0.30319 
X-Powered-By: ASP.NET 
Date: Thu, 09 Feb 2012 10:48:39 GMT 
Content-Length: 441 

Vì vậy, khi theo tôi biết, các trình duyệt sẽ không lưu lại yêu cầu ngay cả khi nó được công khai, vì Vary:* có nghĩa là yêu cầu đã được tạo với các tham số không có trong URL cũng như trong các tiêu đề HTTP. Có cách nào để sửa lỗi này?

Trân trọng.

UPDATE:

Theo cách tương tự, khi tôi gửi hai yêu cầu chứng thực giống hệt nhau, cuộc gọi đầu tiên nhận được private sửa đổi, nhưng không phải là Vary tiêu đề:

HTTP/1.1 200 OK 
Cache-Control: private, max-age=300 
Content-Type: text/html; charset=utf-8 
Expires: Thu, 09 Feb 2012 12:43:14 GMT 
Last-Modified: Thu, 09 Feb 2012 12:38:14 GMT 
Server: Microsoft-IIS/7.5 
X-AspNetMvc-Version: 3.0 
X-AspNet-Version: 4.0.30319 
X-Powered-By: ASP.NET 
Date: Thu, 09 Feb 2012 12:38:14 GMT 
Content-Length: 443 

Nhưng điều thứ hai nhận được phản hồi tương tự rằng yêu cầu không được xác thực:

HTTP/1.1 200 OK 
Cache-Control: public, max-age=298 
Content-Type: text/html; charset=utf-8 
Expires: Thu, 09 Feb 2012 12:44:32 GMT 
Last-Modified: Thu, 09 Feb 2012 12:39:32 GMT 
Vary: * 
Server: Microsoft-IIS/7.5 
X-AspNetMvc-Version: 3.0 
X-AspNet-Version: 4.0.30319 
X-Powered-By: ASP.NET 
Date: Thu, 09 Feb 2012 12:39:33 GMT 
Content-Length: 443 

Tôi đã tải lên một số test project showing the issue vì vậy có thể bạn muốn dùng thử.

Hãy lưu ý rằng có IHttpModule đặt yêu cầu được xác thực hoặc không phụ thuộc vào yêu cầu có cookie hay không, đây không phải là phương pháp "thực tế", nó chỉ dành cho mục đích thử nghiệm.

Dự án chỉ chứa một trang web với một liên kết đến bản thân, một liên kết mà các bản ghi bạn vào, và một đường link khác mà các bản ghi bạn ra ngoài:

  • đăng nhập: Gửi một cookie trong một chuyển hướng HTTP 302 đến nhà một lần nữa.
  • LogOut: Gửi lại cookie đã hết hạn trong một lần truy cập HTTP 302 về trang chủ.

Các dự kiến ​​/ lý tưởng hành vi sẽ là: truy cập

  1. tài Index, và nhận được trang từ máy chủ. Ngày hiển thị trang "A".
  2. Truy cập lại người dùng Chỉ mục và trình duyệt hiển thị phiên bản được lưu trong bộ nhớ cache. Trang hiển thị ngày "A".
  3. Làm sạch bộ nhớ cache của trình duyệt.
  4. Truy cập lại người dùng Chỉ mục và trình duyệt hiển thị phiên bản được lưu trong bộ nhớ cache của máy chủ. Ngày hiển thị trang "A".
  5. Thông tin đăng nhập của người dùng và broswer nhận được một trang mới, hiển thị ngày "B".
  6. Đăng xuất nhấp chuột của người dùng và trình duyệt nhận được trang được lưu trong bộ nhớ cache của máy chủ. Trang hiển thị ngày "A" một lần nữa.

Nhưng đây là hành vi cho đến nay:

  1. truy cập tài khoản Index, và nhận được trang từ máy chủ. Ngày hiển thị trang "A".
  2. Truy cập lại người dùng Chỉ mục và trình duyệt hiển thị phiên bản được lưu trong bộ nhớ cache. Trang hiển thị ngày "A".
  3. Làm sạch bộ nhớ cache của trình duyệt.
  4. Truy cập lại người dùng Chỉ mục và trình duyệt hiển thị phiên bản được lưu trong bộ nhớ cache của máy chủ. Ngày hiển thị trang "A".
  5. Thông tin đăng nhập của người dùng và broswer nhận được một trang mới, hiển thị ngày "B".
  6. Đăng xuất nhấp chuột của người dùng và trình duyệt sẽ nhận được trang được lưu trong bộ nhớ cache của máy chủ nhưng không phải là. Trang hiển thị ngày "B" một lần nữa từ bộ nhớ cache của trình duyệt. Điều này là do thiếu tiêu đề Vary trong phản hồi được xác thực.

Tôi không biết liệu tôi có điều gì sai về bộ nhớ đệm, chỉ thiếu một số chi tiết hoặc OutputCache không hoạt động tốt, nhưng tôi đánh giá cao mọi hướng dẫn.

Chúc mừng.

UPDATE 2:

Ý định của tôi là sử dụng ngữ nghĩa HTTP bộ nhớ cache để:

  1. Cho phép trình duyệt và proxys để cache phiên bản "công cộng" của trang.
  2. Cho phép các trình duyệt lưu vào bộ nhớ cache phiên bản "đã được xác thực" của trang cho người dùng.

Nếu tôi thay đổi tuyên bố OutputCache để làm bộ nhớ đệm chỉ trên máy chủ và ngăn chặn sự hạ lưu và khách hàng bộ nhớ đệm:

[OutputCache(Duration=60*5, Location=OutputCacheLocation.Server, VaryByCustom="index")] 

nó cư xử như mong đợi, nhưng bộ nhớ cache hạ lưu và khách hàng được ngăn chặn, và đó không phải là điều tôi muốn.

+1

Điều gì sẽ xảy ra nếu bạn cũng đặt các thuộc tính VaryBy khác trên thuộc tính OutputCache của phương thức? – bzlm

+0

Tôi đã thêm VaryByHeader = "Cookie", và nó vẫn xảy ra, cuộc gọi thứ hai nhận được một Vary = *. – vtortola

+0

Nếu bạn thử [cách tiếp cận được liên kết trong câu hỏi được liên kết] (http://visitmix.com/writings/using-varybycustom-with-outputcache-in-asp-net-mvc-to-support-caching-for- người dùng đã đăng nhập) như hiện tại, không thay đổi từng cookie hoặc sửa đổi tiêu đề phản hồi bên trong phương thức 'GetVaryByCustom'? (Về mặt kỹ thuật, bạn không cần phải thay đổi theo cookie để đạt được bộ nhớ đệm chỉ dành cho người dùng ẩn danh.) – bzlm

Trả lời

4

Tôi không nghĩ rằng các thuộc tính [OutputCache] là những gì bạn muốn, phương pháp VaryByCustom được về cơ bản nói rằng tôi muốn để cache các phiên bản khác nhau dựa trên các thông số, nó không thực sự có một lựa chọn cho Đừng không cache và phần lớn mã trong thuộc tính được xây dựng dựa trên bộ nhớ đệm dựa trên máy chủ.

Điều đó đang được nói những tài liệu trên MSDN cho bộ nhớ đệm tùy chỉnh dường như chỉ ra bạn cần phải trả lại một chuỗi thay đổi trên dựa trên trạng thái xác thực:

public override string GetVaryByCustomString(HttpContext context, string custom) 
{ 
    if(custom == "user") return "User:" + context.Request.User.Identity.Name; 

    return base.GetVaryByCustomString(context, custom); 
} 

Và sau đó sử dụng người dùng chữ trong VaryByCustom :

[OutputCache(Duration=60*5, Location=OutputCacheLocation.Any, VaryByCustom="user")] 
public ActionResult Index() 
{ 
    return View(); 
} 

Vì vậy, về cơ bản điều này sẽ dẫn đến bộ nhớ cache được tạo ẩn danh (giả sử danh tính ẩn danh là chuỗi trống hoặc thứ gì đó) và mọi người dùng trên máy chủ và Vary: * gửi cho khách hàng tôi tin. Rõ ràng không lý tưởng những gì bạn đang tìm kiếm.

Nếu bạn thực sự chỉ muốn lưu bộ nhớ cache phiên bản chưa được xác thực bằng cách sử dụng bộ đệm ẩn HTTP, tôi khuyên bạn không nên sử dụng OutputCacheAttribute và sử dụng tùy chỉnh nào đó khác.

Bạn có thể dễ dàng chỉ cần viết trong tùy chỉnh của riêng bạn gán một cái gì đó giống như những gì bạn có để thực hiện GetVaryByCustomString của bạn (đây chỉ là một số mã giả, sẽ cần nhiều hơn này):

public class HttpCacheUnauthenticatedAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     if(!filterContext.HttpContext.Request.IsAuthenticated) { 
      //TODO: set unauthenticated caching values and vary here 
     } 
    } 
} 

Và sau đó tag hành động của bạn phương pháp với nó:

[HttpCacheUnauthenticated] 
public ActionResult Index() 
{ 
    return View(); 
} 
+0

Cách tiếp cận với OutputCache đang hoạt động như mong đợi trong cuộc gọi đầu tiên, nó chỉ là trả về tiêu đề Vary sai trong các cuộc gọi tiếp theo, khi các cuộc gọi là một "cache hit" trong OutputCache. Đó là tất cả. Chức năng này được cung cấp nhưng không hoạt động như mong đợi. Thực hiện bộ lọc hành động OutputCache của riêng tôi sẽ không giải quyết bất cứ điều gì. Vấn đề không phải là bản thân OutputCacheAttribute, mà là việc đặt ra bộ nhớ đệm API phía sau. – vtortola

+0

@vtortola Thats lý do tại sao tôi nghĩ bạn nên bỏ qua API và tự viết tiêu đề. Bạn chỉ đang tìm kiếm bộ nhớ đệm HTTP, không phải bộ nhớ đệm phía máy chủ chính xác? Giống như tôi đã nói thuộc tính OutputCache không được thiết kế cho bất kỳ kịch bản nào trong đó nội dung của nó không được lưu trữ trong một phản hồi. –

+0

Không, tôi đang tìm kiếm cả hai: D Đọc kỹ phần "Hành vi mong đợi/lý tưởng sẽ là:". Chúc mừng. – vtortola

0

Tôi đang sử dụng một nhà cung cấp bộ nhớ cache tùy chỉnh và trong trường hợp này có một giải pháp đơn giản cho việc này. Trên BeginRequest, căn cứ vào tình trạng xác thực người dùng, chúng tôi thiết lập một thông tin ngữ cảnh để không chạy cache:

HttpContext.Current.Items["NoCache"] = "1"; 

Và sau đó trên phương pháp GetVaryBy của chúng tôi, chúng tôi trở về null nếu thông tin này được thiết lập:

public override string GetVaryByCustomString(HttpContext context, string custom) 
{ 
    if (HttpContext.Current.Items["NoCache"] != null) 
     return null; 

    // remaining code here 
} 

Và sau đó trên các phương thức cache, chúng ta có thể kiểm tra tương tự. Ví dụ:

public override object Add(string key, object entry, DateTime utcExpiry) 
{ 
    if (HttpContext.Current.Items["NoCache"] != null) 
     return null; 

    // remaining code here 
} 
Các vấn đề liên quan