13

我想让某些页面有一个 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);
    }
}

网络配置设置

  <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 应用程序。

4

3 回答 3

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 但同样您将在缓存持续时间的其他问题中运行(即客户端 10 分钟和服务器 24 小时)

我建议将OutputCache用于客户端缓存,并为服务器端缓存实现您自己的缓存机制。

于 2013-02-19T13:06:46.993 回答
4

在您的 OutputCache 配置文件中,将位置设置为 ServerAndClient。执行此操作后,您的操作过滤器应正确覆盖输出。

于 2013-02-12T03:41:45.937 回答
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 已经发出的内容。最重要的是,您必须附加 max-age 标头。您不能使用 .SetMaxAge(),因为这也设置了服务器缓存的页面副本的最长期限。

这需要相当多的努力才能弄清楚,但它确实有效,至少在 .Net 4.5 中是这样。

于 2014-06-17T17:05:02.153 回答