缓存控制:无存储,必须重新验证未发送到IIS7 + ASP.NET MVC中的客户端浏览器

时间:2014-03-16 22:29:06

标签: c# asp.net-mvc iis-7 http-headers cache-control

我正在尝试确保某个页面永远不会被缓存,并且在用户单击后退按钮时从不显示。 This very highly rated answer (currently 1068 upvotes) says to use

Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");

但是在IIS7 / ASP.NET MVC中,当我发送这些头时,客户端会看到这些响应头:

Cache-control: private, s-maxage=0 // that's not what I set them to
Pragma: no-cache
Expires: 0

缓存控制标头发生了什么变化? IIS7或ASP.NET本机的内容是否会覆盖它?我检查了我的解决方案,我没有覆盖此标题的代码。

当我首先添加Response.Headers.Remove("Cache-Control");时,它没有任何区别:

Response.Headers.Remove("Cache-Control");
Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");

当我添加[OutputCache]属性时:

[OutputCache(Location = OutputCacheLocation.None)]
public ActionResult DoSomething()
{
   Response.Headers.Remove("Cache-Control");
   Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
   Response.AppendHeader("Pragma", "no-cache");
   Response.AppendHeader("Expires", "0");

   var model = DoSomething();
   return View(model);
}

然后客户端响应标头变为:

Cache-control: no-cache
Pragma: no-cache
Expires: 0

哪个更接近,但仍然不是我要发送的标头。这些标题被覆盖的位置在哪里?如何阻止它?

编辑:我已经检查过,错误的标题被发送到Chrome,FF,IE和Safari,所以它看起来是服务器问题,而不是与浏览器相关的问题。

3 个答案:

答案 0 :(得分:36)

通过反复试验,我发现在ASP.NET MVC中为IIS7正确设置标头的一种方法是:

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

第一行将Cache-control设置为no-cache,第二行添加其他属性no-store, must-revalidate

这可能不是唯一的方法,但如果更简单的Response.AppendHeader("Cache-control", "no-cache, no-store, must-revalidate");失败,确实提供了另一种方法。

可以解决的其他相关IIS7缓存控制问题是:

答案 1 :(得分:0)

我想在JK的答案中添加一些内容:
如果将缓存控件的限制值设置为比现有限制更严格,则可以。 (即:在不公开时设置为非缓存)

但是,如果您希望设置的限制值小于已经达到的限制(即:设置为private(当它是非缓存时)),则以下代码将不起作用:

Response.Cache.SetCacheability(HttpCacheability.Private);

因为,SetCacheablitiy方法在下面具有以下代码,并且仅在更具限制性的情况下才设置缓存标志:

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

要在.net mvc中克服此问题,您需要获取HttpResponseMessage的实例,并将CacheControlHeaderValue分配为其Headers.CacheControl的值:

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

操作过滤器中提供HttpResponseMessage的实例。您可以编写一个操作过滤器来设置缓存标头值,如下所示:

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

答案 2 :(得分:0)

如果您在MVC应用程序中全局需要这些标头。添加此类。

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

要全局使用,请将其添加到FilterConfig。

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

或仅在特定控制器上使用这些标头。

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

侧面说明:可以将IIS和web.config用于其他标头。例如,在诸如包(jquery,bootstrap)之类的静态内容上。寻找这些部分customheader,staticcontent。