Cache-control: no-store, must-revalidate not sent to client browser in IIS7 + ASP.NET MVC

后端 未结 3 1131
一生所求
一生所求 2020-12-08 09:57

I am trying to make sure that a certain page is never cached, and never shown when the user clicks the back button. This very highly rated answer (currently 1068 upvotes) s

相关标签:
3条回答
  • 2020-12-08 10:41

    Through trial and error, I have found that one way to set the headers correctly for IIS7 in ASP.NET MVC is:

    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    Response.Cache.AppendCacheExtension("no-store, must-revalidate");
    Response.AppendHeader("Pragma", "no-cache");
    Response.AppendHeader("Expires", "0");
    

    The first line sets Cache-control to no-cache, and the second line adds the other attributes no-store, must-revalidate.

    This may not be the only way, but does provide an alternative method if the more straightforward Response.AppendHeader("Cache-control", "no-cache, no-store, must-revalidate"); fails.

    Other related IIS7 cache-control questions that may be solved by this are:

    • Something is forcing responses to have cache-control: private in IIS7
    • IIS7: Cache Setting Not Working... why?
    • IIS7 + ASP.NET MVC Client Caching Headers Not Working
    • Set cache-control for aspx pages
    • Cache-control: no-store, must-revalidate not sent to client browser in IIS7 + ASP.NET MVC
    0 讨论(0)
  • 2020-12-08 10:41

    I want to add something to JK's answer:
    If you are setting the cache control to a more restrictive value than it already is, it is fine. (i.e: setting no-cache, when it is private)

    But, if you want to set to a less restrictive value than it already is (i.e: setting to private, when it is no-cache), the code below will not work:

    Response.Cache.SetCacheability(HttpCacheability.Private);
    

    Because, SetCacheablitiy method has this code below and sets the cache flag only if it is more restrictive:

    if (s_cacheabilityValues[(int)cacheability] < s_cacheabilityValues[(int)_cacheability]) {
        Dirtied();
       _cacheability = cacheability;
    }
    

    To overcome this in .net mvc, you need to get an instance of HttpResponseMessage and assign a CacheControlHeaderValue to its Headers.CacheControl value:

    actionExecutedContext.Response.Headers.CacheControl = new CacheControlHeaderValue
                                       {
                                           MaxAge = TimeSpan.FromSeconds(3600),
                                           Private = true
                                       };
    

    An instance of the HttpResponseMessage is available in action filters. You can write an action filter to set cache header values like this:

    public class ClientSideCacheAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            var response = actionExecutedContext.ActionContext.Response;
            response.Headers.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue
            {
                MaxAge = TimeSpan.FromSeconds(9999),
                Private = true,
            };
        }
    }
    
    0 讨论(0)
  • 2020-12-08 10:53

    If you need these headers globally in your MVC application. Add this class.

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class CustomHeaders : System.Web.Mvc.ActionFilterAttribute
    {
        [OutputCache(Location = System.Web.UI.OutputCacheLocation.None)]
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            context.RequestContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            context.RequestContext.HttpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate");
            context.RequestContext.HttpContext.Response.AppendHeader("Pragma", "no-cache");
            context.RequestContext.HttpContext.Response.AppendHeader("Expires", "0");
    
            base.OnActionExecuted(context);
        }
    }
    

    For global use add it to the FilterConfig.

    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
            filters.Add(new CustomHeaders());
        }
    }
    

    Or only use these headers on a specific controller.

    [Authorize]
    [CustomHeaders]
    public class HomeController : Controller
    {
        [AllowAnonymous]
        public ActionResult Index()
    

    Side note: you can use IIS and web.config for other headers. For example on static content like your bundles (jquery,bootstrap). Look for these sections customheaders, staticcontent.

    0 讨论(0)
提交回复
热议问题