【问题标题】:Cache-control: no-store, must-revalidate not sent to client browser in IIS7 + ASP.NET MVC缓存控制:在 IIS7 + ASP.NET MVC 中,没有存储、必须重新验证未发送到客户端浏览器
【发布时间】:2014-04-22 01:01:01
【问题描述】:

我试图确保某个页面永远不会被缓存,并且当用户单击后退按钮时永远不会显示。 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,所以它看起来是服务器问题而不是浏览器相关问题。

【问题讨论】:

  • 我无法在新的 MVC3 或 MVC4 应用程序中复制此问题。您能检查一下您在 IIS 中的设置(HTTP 响应标头输出缓存)吗?
  • 在 IIS7 中,我没有为输出缓存(服务器级别或站点级别)配置任何设置,并且只配置了一个响应标头(X-Powered-By)

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


【解决方案1】:

通过反复试验,我发现在 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 缓存控制问题可能由此解决:

【讨论】:

  • 我喜欢 MVC 和 IIS 只是决定在这里和那里随机中断自己的 API 并引入静默失败。
  • 也可以在 IIS 8 上工作,这个答案也是如此:stackoverflow.com/a/33065747/318411
  • 这是唯一对我有用的东西,即使在 Windows 10 上的 IIS 10 上也是如此。谢谢!设置“无缓存”标头的其他答案不会导致输出“无存储”值,这会导致浏览器缓存一些内容并在用户使用后退/前进浏览器按钮导航时加载它。跨度>
  • 我通过 Global.asax.cs 和控制器操作过滤器强制 IIS 将响应标头设置为“私有,无存储,max-age=0”,但 IIS 显示为“公共,无-商店,最大年龄=0”。最后,这种方法在 IIS 10 中也适用于我。很好的帮助!
【解决方案2】:

我想在JK的回答中添加一些内容:
如果您将缓存控件设置为比现在更严格的值,那很好。 (即:设置无缓存,当它是私有的)

但是,如果你想设置一个比它已经设置的限制更少的值(即:设置为私有,当它是无缓存时),下面的代码将不起作用: p>

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

【讨论】:

  • ActionFilterAttribute OnActionRequested 似乎需要一个 ActionExecutedContext 而不是 HttpActionExecutedContext 。 ActionExecutedContext 不允许访问 ActionContext(只有 HttpContext.Response.Headers,没有 CacheControl)有什么想法吗? (注意 MVC 不是 WebAPI)
【解决方案3】:

如果您在 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)。查找这些部分 customheaders、staticcontent。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-25
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多