2013-02-11 82 views
12

我希望某些頁面有10分鐘的客戶端緩存和24小時的服務器緩存。原因是,如果頁面更改,客戶端將在10分鐘內獲取更新的版本,但如果沒有任何更改,服務器將只需每天重新生成一次頁面。如何爲客戶端和服務器緩存設置不同的緩存過期時間

問題是輸出緩存設置似乎覆蓋客戶端設置。這裏是我的設置:

定製ActionFilterAttribute類

public class ClientCacheAttribute : ActionFilterAttribute 
{ 
    private bool _noClientCache; 

    public int ExpireMinutes { get; set; } 

    public ClientCacheAttribute(bool noClientCache) 
    { 
     _noClientCache = noClientCache; 
    } 

    public override void OnResultExecuting(ResultExecutingContext filterContext) 
    { 
     if (_noClientCache || ExpireMinutes <= 0) 
     { 
      filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1)); 
      filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false); 
      filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches); 
      filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache); 
      filterContext.HttpContext.Response.Cache.SetNoStore(); 
     } 
     else 
     { 
      filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(ExpireMinutes)); 
     } 

     base.OnResultExecuting(filterContext); 
    } 
} 

Web配置設置

<outputCacheSettings> 
    <outputCacheProfiles> 
     <add name="Cache24Hours" location="Server" duration="86400" varyByParam="none" /> 
    </outputCacheProfiles> 
    </outputCacheSettings> 

如何,我叫它:

[OutputCache(CacheProfile = "Cache24Hours")] 
[ClientCacheAttribute(false, ExpireMinutes = 10)] 
public class HomeController : Controller 
{ 
    [...] 
} 

但廁所國王在HTTP標頭顯示:

HTTP/1.1 200 OK 
Cache-Control: no-cache 
Pragma: no-cache 
Content-Type: text/html; charset=utf-8 
Expires: -1 

我該如何正確實施這個?它是一個ASP.NET MVC 4應用程序。

+0

我不熟悉這種緩存語法。我使用持續時間。與它取得成功。這對您的調試沒有幫助,但它的替代建議 – 2013-02-11 23:47:48

回答

4

在您的OutputCache配置文件中,將位置設置爲ServerAndClient。一旦你做到這一點,你的行爲過濾器應該正確地覆蓋輸出。

+0

這樣做會將最大年齡值添加到標題,但也會設置Expires: HTTP/1.1 200 OK Cache-Control:private,max-age = 86400 內容類型:text/html; charset = utf-8 過期時間:週二,2013年2月12日13:33:41 GMT – Josh 2013-02-12 13:35:37

+0

我不是100%確定最終結果是什麼,但我認爲如果您將調用添加到Response.Cache.SetMaxAge在你的動作過濾器中,CC:max-age和Expires會匹配起來,你會很開心。 – pauln 2013-02-12 19:39:14

+0

我試着設置Response.Cache.SetMaxAge,並在ServerAndClient模式下被輸出緩存覆蓋。只在過濾模式下忽略。我的目標是將Cache-Control設置爲「public,max-age = 10」,並從現在開始(GMT)過期10分鐘。緩存控制由輸出緩存控制,似乎我無法覆蓋它。 – Josh 2013-02-12 21:21:28

8

您需要爲服務器端緩存和客戶端緩存實現自己的解決方案,可以使用ClientCacheAttribute或OutputCache。這就是爲什麼您需要您的自定義解決方案的服務器端緩存的原因。

  • ClientCacheAttribute集緩存策略,以Response.Cache這是HttpCachePolicyBase
  • 型和內置的OutputCache還設置緩存策略,以Response.Cache

在這裏,我什麼試圖突出的是,we don't have collection of HttpCachePolicyBase but we only have one object of HttpCachePolicyBase so we can't set multiple cache policy for given response.

即使我們可以將Http Cacheability設置爲HttpCacheability.ServerAndPrivate,但是agai ñ你將運行在其他問題緩存持續時間(即客戶端10分鐘&服務器24小時)

我的建議是客戶端緩存在使用的OutputCache和執行服務器端緩存你自己的緩存機制。

+0

我試圖避免這種情況,創建一個自定義的客戶端(基本上管理http頭文件)要容易得多,然後創建一個自定義的服務器端解決方案,因爲您必須在緩存中管理頁面副本。不幸的是,當我嘗試讓OutputCache管理服務器緩存時,它覆蓋了我爲客戶端手動設置的http標頭。你知道一種覆蓋輸出緩存在服務器模式下設置的http頭的方法嗎? – Josh 2013-02-19 14:31:34

+0

Josh很可能會發生,這也是顯而易見的,因爲在執行結果後邏輯結果被緩存,而在大多數情況下,我們通過操作方法管理頭部或執行結果之前 – 2013-02-19 17:43:12

+0

,這就是爲什麼我建議使用OutputCache作爲客戶端,因爲只需設置響應不推薦使用頭部,而是使用高速緩存策略進行客戶端緩存 – 2013-02-19 17:45:10

3

在.NET 4.5,這是可能的,而無需編寫自定義緩存供應商有不同的客戶端和服務器緩存策略:

// Set the cache response expiration to 3600 seconds (use your own value here). 
HttpContext.Current.Response.Cache.SetExpires(DateTime.UtcNow.AddSeconds(3600)); 

// Set both server and browser caching. 
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate); 

// Prevent browser's default max-age=0 header on first request 
// from invalidating the server cache on each request. 
HttpContext.Current.Response.Cache.SetValidUntilExpires(true); 

// Set an HTTP ETag header on the page using a random GUID. 
HttpContext.Current.Response.Cache.SetETag(System.Guid.NewGuid() 
              .ToString().Replace("-", "")); 

// Set last modified time. 
HttpContext.Current.Response.Cache.SetLastModified(DateTime.UtcNow); 

// Now here is the critical piece that forces revalidation on each request!: 
HttpContext.Current.Response.Cache.AppendCacheExtension(
    "must-revalidate, proxy-revalidate, max-age=0"); 

結果是每個頁面獲取服務器緩存再生的時候,它會一個新的ETag。這會導致If-None-Match請求將完整頁面返回給瀏覽器。如果瀏覽器的緩存副本與服務器緩存(同一ETag)中生成的副本相同,則瀏覽器會返回304 Not Modified。

請注意,我附加在AppendCacheExtension中的緩存標頭與本機緩存發出的標頭沒有衝突。每當你嘗試修改由.Net緩存本身發出的緩存頭時,.Net將總是取代你想要做的事情。訣竅是添加新的非衝突標頭,而不是嘗試改變.Net已經發出的東西。最重要的是,您必須添加最大年齡標題。您不能使用.SetMaxAge(),因爲這也會設置頁面的服務器緩存副本的最大使用期限。

這需要花費很多努力才能弄清楚,但它至少在.Net 4.5中起作用。

+0

這不是在技術上設置不同的客戶端緩存時間,我認爲最後一行與設置HttpContext.Current.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches)沒有區別;我提高了答案,因爲使用此解決方法比重新實現服務器端緩存要好得多。客戶端重新驗證緩存對服務器的開銷很小,所以我認爲這是一個很好的答案。 – madamission 2016-02-24 18:34:12

相關問題