我有一个我想要缓存的动作方法:
[OutputCache(Duration=60*5, Location=OutputCacheLocation.Any, VaryByCustom="index")]
public ActionResult Index()
{
return View();
}
采用这种方法:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
context.Response.Cache.SetOmitVaryStar(true);
context.Response.Cache.VaryByHeaders["Cookie"] = true;
if (User.Identity.IsAuthenticated)
{
Debug.Print("Authenticated");
context.Response.Cache.SetNoServerCaching();
context.Response.Cache.SetCacheability(HttpCacheability.Private);
return null;
}
else
{
Debug.Print("Non authenticated");
return custom;
}
}
我认为它总会返回Vary:Cookie
HTTP标头,但事实并非如此。
使用Fiddler进行测试并发出两次相同的请求,在第一次HTTP调用中它很顺利:
HTTP/1.1 200 OK
Cache-Control: public, max-age=300
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2012 10:53:36 GMT
Last-Modified: Thu, 09 Feb 2012 10:48:36 GMT
Vary: Cookie
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 09 Feb 2012 10:48:37 GMT
Content-Length: 441
但在第二个中,它会覆盖标题:
HTTP/1.1 200 OK
Cache-Control: public, max-age=297
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2012 10:53:36 GMT
Last-Modified: Thu, 09 Feb 2012 10:48:36 GMT
Vary: *
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 09 Feb 2012 10:48:39 GMT
Content-Length: 441
因此,据我所知,浏览器即使是公共的,也不会缓存请求,因为Vary:*
表示请求是使用不在URL中的参数生成的,也不是在HTTP头中生成的。有办法解决这个问题吗?
问候。
更新
以类似的方式,当我发送两个相同的经过身份验证的请求时,第一个调用会获得private
修饰符,但不会获得Vary
标题:
HTTP/1.1 200 OK
Cache-Control: private, max-age=300
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2012 12:43:14 GMT
Last-Modified: Thu, 09 Feb 2012 12:38:14 GMT
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 09 Feb 2012 12:38:14 GMT
Content-Length: 443
但是第二个获得与未经过身份验证的请求相同的响应:
HTTP/1.1 200 OK
Cache-Control: public, max-age=298
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2012 12:44:32 GMT
Last-Modified: Thu, 09 Feb 2012 12:39:32 GMT
Vary: *
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 09 Feb 2012 12:39:33 GMT
Content-Length: 443
我上传了test project showing the issue,所以您可能想尝试一下。
请注意,有一个IHttpModule
将请求设置为已验证或不取决于请求是否包含Cookie,这不是“现实生活”方法,仅用于测试目的
该项目仅包含一个带有自身链接的网页,一个登录您的链接以及另一个将您注销的链接:
HTTP 302
重定向中的cookie发送到主页。HTTP 302
重定向中过期的Cookie发送到主页。期望/理想行为将是:
但到目前为止这是行为:
Vary
标头。我不知道我是否对缓存有任何不妥之处,只是遗漏了一些细节或者OutputCache
不能很好地工作,但我会很感激任何指导。
干杯。
更新2:
我的目的是使用HTTP缓存语义:
如果我更改OutputCache声明只在服务器上执行缓存并阻止下游和客户端缓存:
[OutputCache(Duration=60*5, Location=OutputCacheLocation.Server, VaryByCustom="index")]
它的行为符合预期,但是防止了下游和客户端缓存,这不是我想要的。
答案 0 :(得分:4)
我认为[OutputCache]
属性不是你想要的,VaryByCustom
方法基本上是说我想根据这些参数缓存不同的版本,它实际上没有选项对于不缓存,属性中的大部分代码都是围绕基于服务器的缓存构建的。
据说MSDN上有关自定义缓存的文档似乎表明你需要根据身份验证状态返回一个字符串:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if(custom == "user") return "User:" + context.Request.User.Identity.Name;
return base.GetVaryByCustomString(context, custom);
}
然后使用VaryByCustom
中的用户文字:
[OutputCache(Duration=60*5, Location=OutputCacheLocation.Any, VaryByCustom="user")]
public ActionResult Index()
{
return View();
}
所以基本上这会导致为匿名构建缓存(假设匿名身份是空字符串或其他东西)和服务器上的每个用户,并且我相信发送给客户端的Vary: *
。显然不是你想要的。
如果您真的只想使用HTTP缓存来缓存未经身份验证的版本,我建议您不要使用OutputCacheAttribute
并使用更多自定义内容。
您可以轻松地在自己的自定义属性中编写类似于GetVaryByCustomString
实现的内容(这只是一些伪代码,需要更多代码):
public class HttpCacheUnauthenticatedAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if(!filterContext.HttpContext.Request.IsAuthenticated) {
//TODO: set unauthenticated caching values and vary here
}
}
}
然后用它标记你的行动方法:
[HttpCacheUnauthenticated]
public ActionResult Index()
{
return View();
}
答案 1 :(得分:1)
与我自己类似的摔跤。您是否尝试过使用web.config进行设置omitVaryStar=true
https://msdn.microsoft.com/en-us/library/ms228124(v=vs.100).aspx
答案 2 :(得分:0)
我正在使用自定义缓存提供程序,在这种情况下,有一个简单的解决方案。 在BeginRequest上,根据用户身份验证状态,我们将上下文信息设置为不运行缓存:
HttpContext.Current.Items["NoCache"] = "1";
然后在我们的GetVaryBy方法中,如果设置了此信息,则返回null:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if (HttpContext.Current.Items["NoCache"] != null)
return null;
// remaining code here
}
然后在缓存方法上,我们可以测试相同的。例如:
public override object Add(string key, object entry, DateTime utcExpiry)
{
if (HttpContext.Current.Items["NoCache"] != null)
return null;
// remaining code here
}