禁用所有操作的浏览器缓存,但保留捆绑包

时间:2014-05-15 14:53:18

标签: c# asp.net-mvc browser-cache

在我正在处理的MVC应用程序中,出于安全原因,我们不得不在所有操作上阻止浏览器缓存(防止用户在注销后返回历史记录)。我们使用this solution实现了这一目标。

但是,我们确实希望允许浏览器缓存css和js包。不幸的是,上面提到的解决方案似乎阻止了所有资源的缓存。在本地机器上,它甚至包括静态文件,如图像,但在远程服务器上IIS处理这些文件(而不是应用程序本身),因此不必担心。无论如何,有没有办法调整这个解决方案,以允许浏览器缓存捆绑包?

我知道我可以使用像this one这样的过滤器并将其添加到所有操作(甚至更好,所有控制器)或添加一个新的基本控制器,默认情况下具有此过滤器,并设置所有控制器继承它,但有没有更好的选择(不涉及改变项目中的无数文件)?

P.S。写完这个问题让我想到了一些我必须尝试的解决方案。这件事发生在我之前。我的意思是,在这里写一个问题时找到正确的答案,但我最后没有发布这些问题。


在写这个问题时,我看到的解决方案非常简单。只需在if内写一个简单的Application_BeginRequest条件,根据请求网址确定资源是否应该可缓存...我还没有测试过它,但听起来像它可能只是做这个工作。

2 个答案:

答案 0 :(得分:4)

我们使用全局过滤器完成了您的原始要求。在Global.asax.cs中:

GlobalFilters.Filters.Add(new NoCacheAttribute());

NoCacheAttribute:

/// <summary>
/// An attribute that can be attached to an individual controller or used globally to prevent the browser from caching the response.
/// This has nothing to do with server side caching, it simply alters the response headers with instructions for the browser.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class NoCacheAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        if (!filterContext.IsChildAction && !(filterContext.Result is FileResult))
        {
            filterContext.HttpContext.Response.Cache.SetExpires(DateTime.MinValue);
            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();
            base.OnResultExecuting(filterContext);
        }
    }
}

这会影响我们所有的控制器操作,但只留下静态内容和其他所有内容。 Bundling框架处理它自己的缓存:它基本上告诉浏览器永远缓存,但在URL中包含一个缓存清除令牌,如果修改了任何捆绑文件,则该哈希值会发生变化。此机制不受此过滤器的影响。 (我不知道是不是因为没有应用全局过滤器,或者因为它产生了FileResult - 我怀疑是前者。)

答案 1 :(得分:2)

这是我在原始问题中提到的解决方案。它非常简单(有点脏),但似乎有用。

protected void Application_BeginRequest()
{
    // Here we check if the request was for bundle or not and depending on that
    // apply the cache block.
    if (!Request.Url.PathAndQuery.StartsWith("/bundles/"))
    {
        Response.Cache.SetAllowResponseInBrowserHistory(false);
        Response.Cache.SetCacheability(HttpCacheability.NoCache);
        Response.Cache.SetNoStore();
        Response.Cache.SetExpires(DateTime.Now);
        Response.Cache.SetValidUntilExpires(true);
    }
}

在我的本地环境中,我还在条件中添加了/Content/文件夹,但它在远程服务器上是多余的,因为IIS将处理这些(除非您明确告诉它不要)。