简体   繁体   English

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

[英]Disable browser cache for all actions, but keep it for bundles

In an MVC App that I'm working on, we had to block browser cache on all actions for security reasons (preventing user from going back in history after he has logged out). 在我正在处理的MVC应用程序中,出于安全原因,我们不得不在所有操作上阻止浏览器缓存(防止用户在注销后返回历史记录)。 We achieved this using this solution . 我们使用此解决方案实现了此目

However, we do want to allow browsers to cache css and js bundles. 但是,我们确实希望允许浏览器缓存css和js包。 Unfortunately the solution mentioned above appears to block caching of all resources. 不幸的是,上面提到的解决方案似乎阻止了所有资源的缓存。 On local machine it even includes static files like images, though on remote server IIS handles those files (rather than the App itself) so that's one less thing to worry about. 在本地机器上,它甚至包括静态文件,如图像,但在远程服务器IIS上处理这些文件(而不是应用程序本身),这样就不用担心了。 Anyway, is there some way to tweak this solution to allow bundles to be cached by browser? 无论如何,是否有一些方法可以调整此解决方案以允许浏览器缓存捆绑包?

I know that I could use a filter like this one and add it to all the actions (or even better, all controllers) or add a new base controller, that has this filter by default, and set all my controllers to inherit from it, but are there any better alternatives (ones that don't involve changing myriad files in the project)? 我知道我可以使用像这样的过滤器并将其添加到所有操作(甚至更好,所有控制器)或添加一个新的基本控制器,默认情况下具有此过滤器,并将所有控制器设置为继承它,但有没有更好的替代方案(不涉及更改项目中的无数文件)?

PS Having written this question has made me think of a few solutions that I have to try. PS写完这个问题让我想到了一些我必须尝试的解决方案。 This happened to me before. 这件事发生在我之前。 I mean, finding the right answer while writing a question here, but I ended up not posting those questions. 我的意思是,在这里写一个问题时找到正确答案,但我最终没有发布这些问题。


The solution which appeared to me while writing this question is really simple. 在写这个问题时,我看到的解决方案非常简单。 Just write a simple if condition inside of Application_BeginRequest to determine if the resource should be cacheable or not based on the request url... I haven't tested it yet, but it sounds like it might just do the job. 只需在Application_BeginRequest写一个简单的if条件,根据请求url确定资源是否应该是可缓存的......我还没有测试它,但听起来它可能就是这样做的。

We accomplished your original requirement using a global filter. 我们使用全局过滤器完成了您的原始要求。 In Global.asax.cs: 在Global.asax.cs中:

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

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

This affects all of our controller actions, but leaves static content and everything else alone. 这会影响我们所有的控制器操作,但只留下静态内容和其他所有操作。 The Bundling framework handles its own caching: it basically tells browsers to cache forever, but includes a cache-busting token in the URL, which is a hash that changes if any of the bundled files are modified. Bundling框架处理它自己的缓存:它基本上告诉浏览器永远缓存,但在URL中包含一个缓存清除令牌,如果修改了任何捆绑文件,则该哈希值会发生变化。 This mechanism is unaffected by this filter. 此机制不受此过滤器的影响。 (I don't know if that's because global filters are not applied, or because it produces a FileResult--I suspect the former.) (我不知道是不是因为没有应用全局过滤器,或者因为它产生了FileResult - 我怀疑是前者。)

Here is the solution that I mentioned in the original question. 这是我在原始问题中提到的解决方案。 It's very simple (and somewhat dirty), but it appears to work. 这很简单(有点脏),但似乎有效。

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

In my local envoriment I also added /Content/ folder to the condition, but it's redundant on the remote server, since IIS will handle those (unless you explicitly tell it not to). 在我的本地环境中,我还将/Content/文件夹添加到条件中,但它在远程服务器上是多余的,因为IIS将处理这些(除非您明确告诉它不要)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM