如何在MVC 3应用程序中添加站点范围的no-cache头信息

25
我建立了一个MVC3应用程序,这个应用程序有很多页面。由于安全问题,现在我需要在HTTP头部添加no-cache设置。是否有更容易的方法来做到这一点?如果我们可以修改一个地方,那么它将适用于整个应用程序,那将是完美的。
你们能帮帮我吗?

我已经编辑了我的答案,使用Response.Cache.SetCacheability()方法而不是手动设置头。在Fiddler中测试并按预期工作。 - Marko
5个回答

37

Global.asax 中的 Application_PreSendRequestHeaders 事件中设置 Headers 怎么样?

编辑 你可以使用 Response.Cache.SetCacheability 而不是直接设置 Headers.*

void Application_PreSendRequestHeaders(Object sender, EventArgs e)
{
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
}

在Fiddler中测试过。


通过手动设置头部信息也可以实现。

void Application_PreSendRequestHeaders(Object sender, EventArgs e) {
    Response.Headers.Set("Cache-Control", "no-cache");
}

13
这太多不缓存了!如果这样做,你将不缓存所有的JavaScript、CSS、图标等,会对你的带宽和响应能力造成很大影响。 - Scott Stafford
2
@ScottStafford阅读了原帖的要求:“如果我们可以修改一个地方,那么它将适用于整个应用程序,那将是完美的。”显然,有些文件可以进行筛选,但这并不是原帖的要求。 - Marko
4
我知道他说了那句话。我没有做任何-1或其他事情,但我想确保他(和任何其他读者)知道这种强硬方法的后果。加入一个“这是一个aspx文件吗”的测试,它就更广泛适用。 - Scott Stafford
@ScottStafford,那个(.aspx过滤器)在MVC中并不能起作用,但是应该进行类似的过滤。 - ps2goat

14

提供给那些想要方法/操作或类/控制器范围内的no-cache的替代方法

[OutputCache(Location = OutputCacheLocation.None)]
public class HomeController : Controller
{
...
}

如此解释:

OutputCacheLocation 枚举

None : 对请求的页面禁用输出缓存。 此值对应于 HttpCacheability.NoCache 枚举值。

HttpCacheability 枚举

NoCache - 设置 Cache-Control:no-cache 头....


ASP.NET的输出缓存与OP所询问的no-cache HTTP头不同。 - Mike Marynowski
@MikeMarynowski 是的,但你确定吗?我认为None表示既不是服务器也不是客户端,并为客户端生成“Cache-Control: no-cache”头。 - KCD
"None: 请求的页面未启用输出缓存。此值对应于 HttpCacheability.NoCache 枚举值。" ... "NoCache - 设置 Cache-Control: no-cache 标头...." - KCD
嗯,这很有意思,我从来没有看到过这种用法来防止客户端缓存,但我想我改变了立场。如果是这样,我不知道为什么这种方法不经常使用和建议 - 我几乎只看到建议使用Response.Cache.SetCacheability。你的方法更符合MVC的风格。 - Mike Marynowski
如果你能编辑你的答案并添加一行关于那个问题的说明,我会点赞 - 这将锁定负评,除非答案被编辑过。 - Mike Marynowski

2
设置全局过滤器。
public class MvcApplication : System.Web.HttpApplication
{

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new NoCacheGlobalActionFilter());
    }    
}

public class NoCacheGlobalActionFilter : ActionFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
        cache.SetCacheability(HttpCacheability.NoCache);

        base.OnResultExecuted(filterContext);
    }
}

http://dotnet.dzone.com/articles/output-caching-aspnet-mvc


1

我会在IIS本身中完成它(假设您正在使用它),或者在web.config文件中完成:

<configuration>
   <system.webServer>
      <staticContent>
         <clientCache cacheControlMode="DisableCache" />
      </staticContent>
   </system.webServer>
</configuration>

代码越少,越好。

根据IIS的版本,设置略有不同。

更多信息请参见此处


这个配置只适用于静态内容(img、js、css等),还是名称有点误导?从IIS网站上并不太清楚。 - Troy Hunt
@Troy - 我认为一切都没问题。很容易测试,只需在Fiddler / Firebug /等中检查响应头即可。 - RPM1984
2
从应用程序控制缓存对我来说似乎更合适,因为我预计大多数人都希望缓存静态内容。此外,我不会说你的解决方案需要更少的代码 :-)。 - theDmi
它确实需要较少的代码。只需更改web.config即可。换句话说,它不必重新编译和修补,并且如果需要,它可以进入根web.config并应用于整个站点。顺便说一下,谢谢,这正是我在寻找的! - PhilDearmore

1
我建议将这些调用限制为非GET请求,以避免在GET请求上失去缓存的好处。以下内容确保即使是像iOS 6 Safari这样具有侵略性缓存的浏览器也不会缓存任何非GET请求的内容。
我使用一个控制器基类,所有我的控制器都继承自该基类,出于许多原因,这对我很有帮助,因为我的Initialize重写可以有条件地处理设置缓存标头。
public class SmartController : Controller
{
    ...
    public HttpContextBase Context { get; set; }

    protected override void Initialize(System.Web.Routing.RequestContext requestContext)
    {
        Context = requestContext.HttpContext;

        if (Context.Request.RequestType != "GET")
        {
            Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        }

        base.Initialize(requestContext);
        ...
    }
...
}

基于HTTP动词设置缓存策略并不足以满足各种应用程序的需求。比如说,你有一个页面,在该页面中使用GET和查询字符串来加载医院患者数据?你不希望该页面被缓存。 - Larry Silverman
在这种情况下,您肯定不想像我在这里建议的那样实现基本控制器逻辑。 :) - Jim Speaker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接