lea*_*ing 39 .net asp.net asp.net-mvc asp.net-mvc-3
我最近遇到了Last-Modified Header.
我想要一个例子,如何将最后修改的头文件包含在mvc项目中,对于静态页面和数据库查询也是如此?
它与outputcache有什么不同,如果是的话怎么样?
基本上,我希望浏览器清除缓存并自动显示最新的数据或页面,而无需用户刷新或清除缓存.
jga*_*fin 47
将Last-Modified主要用于高速缓存.它会被回送给您可以跟踪修改时间的资源.资源不一定是文件,而是任何东西.例如,您从具有UpdatedAt列的dB信息生成的页面.
它与If-Modified-Since每个浏览器在Request中发送的标头结合使用(如果它Last-Modified先前已收到标头).
如何以及在何处将其包含在MVC中?
包含它有什么好处?
为动态生成的页面启用细粒度缓存(例如,您可以将DB字段UpdatedAt用作最后修改的标头).
例
要使一切正常,你必须做这样的事情:
public class YourController : Controller
{
public ActionResult MyPage(string id)
{
var entity = _db.Get(id);
var headerValue = Request.Headers['If-Modified-Since'];
if (headerValue != null)
{
var modifiedSince = DateTime.Parse(headerValue).ToLocalTime();
if (modifiedSince >= entity.UpdatedAt)
{
return new HttpStatusCodeResult(304, "Page has not been modified");
}
}
// page has been changed.
// generate a view ...
// .. and set last modified in the date format specified in the HTTP rfc.
Response.AddHeader('Last-Modified', entity.UpdatedAt.ToUniversalTime().ToString("R"));
}
}
Run Code Online (Sandbox Code Playgroud)
您可能必须在DateTime.Parse中指定格式.
免责声明:我不知道ASP.NET/MVC3是否支持您Last-Modified自己管理.
更新
您可以创建一个扩展方法:
public static class CacheExtensions
{
public static bool IsModified(this Controller controller, DateTime updatedAt)
{
var headerValue = controller.Request.Headers['If-Modified-Since'];
if (headerValue != null)
{
var modifiedSince = DateTime.Parse(headerValue).ToLocalTime();
if (modifiedSince >= updatedAt)
{
return false;
}
}
return true;
}
public static ActionResult NotModified(this Controller controller)
{
return new HttpStatusCodeResult(304, "Page has not been modified");
}
}
Run Code Online (Sandbox Code Playgroud)
然后像这样使用它们:
public class YourController : Controller
{
public ActionResult MyPage(string id)
{
var entity = _db.Get(id);
if (!this.IsModified(entity.UpdatedAt))
return this.NotModified();
// page has been changed.
// generate a view ...
// .. and set last modified in the date format specified in the HTTP rfc.
Response.AddHeader('Last-Modified', entity.UpdatedAt.ToUniversalTime().ToString("R"));
}
}
Run Code Online (Sandbox Code Playgroud)
VJA*_*JAI 18
更新:检查我的新答案
如何以及在何处将其包含在MVC中?
内置OutputCache过滤器为您完成工作,它使用这些标头进行缓存.设置as 或时,OuputCache过滤器使用Last-Modified标题.LocationClientServerAndClient
[OutputCache(Duration = 60, Location = "Client")]
public ViewResult PleaseCacheMe()
{
return View();
}
Run Code Online (Sandbox Code Playgroud)
包含它有什么好处?
利用条件缓存刷新的客户端缓存
我想要一个例子,如何将最后修改的头文件包含在mvc项目中,对于静态页面和数据库查询也是如此?
此链接包含足够的信息来试用样本.对于像html这样的静态页面,图像IIS将负责设置/检查Last-Modified标题,并使用文件的上次修改日期.对于数据库查询,你可以去设置SqlDependency的OutputCache.
是不同的outputcache,如果是的如何?我什么时候需要包含Last-Modified Header以及何时使用outputcache?
OutputCache是一个用于在ASP.NET MVC中实现缓存机制的动作过滤器.您可以使用OutputCache以下方法执行缓存:客户端缓存,服务器端缓存.Last-Modifiedheader是在客户端完成缓存的一种方法.OutputCachefilter设置Locationas 时使用它Client.
如果您进行客户端缓存(Last-Modified或ETag),浏览器缓存将在后续请求中自动更新,您不需要执行F5.
Luk*_*ied 15
该的OutputCache属性上的IIS web服务器控件输出缓存.这是供应商特定的服务器功能(请参阅配置IIS 7输出缓存).如果您对此技术的强大功能感兴趣,我还建议您阅读ASP.NET MVC3中的Cache Exploration.
Last-Modified响应头及其对应的If-Modified-Since请求头是验证缓存概念的代表(部分缓存控制).这些头是HTTP协议的一部分,在rfc4229中指定
OutputCache和验证不是独占的,您可以将它组合起来.
什么缓存方案让我开心?
像往常一样:这取决于.
在100次/秒页面上配置5秒OutputCache将大大减少负载.使用OutputCache,可以从缓存中提供500个命中中的499个(并且不需要花费db往返,计算,渲染).
当我必须立即服务很少更改时,验证方案可以节省很多带宽.特别是当您提供大型内容而不是精简304状态消息时.但是,由于每个请求都会验证源中的更改,因此会立即采用更改.
根据我的经验,我建议将验证方案(最后修改)实现为操作过滤器属性.(顺便说一下:这是一个作为属性实现的其他缓存场景)
来自文件的静态内容
[LastModifiedCache]
public ActionResult Static()
{
return File("c:\data\static.html", "text/html");
}
Run Code Online (Sandbox Code Playgroud)
动态内容示例
[LastModifiedCache]
public ActionResult Dynamic(int dynamicId)
{
// get data from your backend (db, cache ...)
var model = new DynamicModel{
Id = dynamivId,
LastModifiedDate = DateTime.Today
};
return View(model);
}
public interface ILastModifiedDate
{
DateTime LastModifiedDate { get; }
}
public class DynamicModel : ILastModifiedDate
{
public DateTime LastModifiedDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
LastModifiedCache属性
public class LastModifiedCacheAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Result is FilePathResult)
{
// static content is served from file in my example
// the last file write time is taken as modification date
var result = (FilePathResult) filterContext.Result;
DateTime lastModify = new FileInfo(result.FileName).LastWriteTime;
if (!HasModification(filterContext.RequestContext, lastModify))
filterContext.Result = NotModified(filterContext.RequestContext, lastModify);
SetLastModifiedDate(filterContext.RequestContext, lastModify);
}
if (filterContext.Controller.ViewData.Model is HomeController.ILastModifiedDate)
{
// dynamic content assumes the ILastModifiedDate interface to be implemented in the model
var modifyInterface = (HomeController.ILastModifiedDate)filterContext.Controller.ViewData.Model;
DateTime lastModify = modifyInterface.LastModifiedDate;
if (!HasModification(filterContext.RequestContext, lastModify))
filterContext.Result = NotModified(filterContext.RequestContext, lastModify);
filterContext.RequestContext.HttpContext.Response.Cache.SetLastModified(lastModify);
}
base.OnActionExecuted(filterContext);
}
private static void SetLastModifiedDate(RequestContext requestContext, DateTime modificationDate)
{
requestContext.HttpContext.Response.Cache.SetLastModified(modificationDate);
}
private static bool HasModification(RequestContext context, DateTime modificationDate)
{
var headerValue = context.HttpContext.Request.Headers["If-Modified-Since"];
if (headerValue == null)
return true;
var modifiedSince = DateTime.Parse(headerValue).ToLocalTime();
return modifiedSince < modificationDate;
}
private static ActionResult NotModified(RequestContext response, DateTime lastModificationDate)
{
response.HttpContext.Response.Cache.SetLastModified(lastModificationDate);
return new HttpStatusCodeResult(304, "Page has not been modified");
}
}
Run Code Online (Sandbox Code Playgroud)
如何启用全局LastModified支持
您可以将LastModifiedCache属性添加到global.asax.cs的RegisterGlobalFilters部分,以在mvc项目中全局启用此类缓存.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
...
filters.Add(new LastModifiedCacheAttribute());
...
}
Run Code Online (Sandbox Code Playgroud)
请注意,outputcache 并不是您唯一的选择,事实上您可能不希望以它的方式处理 Last-modified。澄清几个选项:
选项 1 - 使用 [OutputCache]
在这种情况下,框架将根据您指定的任何持续时间缓存响应正文。它会将 Last-Modified 设置为当前时间,并将 max-age 设置为原始缓存持续时间到期之前的剩余时间。如果客户端发送带有 If-Modified-Since 的请求,则框架将正确返回 304。一旦缓存的响应过期,则每次缓存新响应时都会更新 Last-Modified 日期。
选项 2 - 指定 Response.Cache 的设置
asp.net 在outputcacheattribute 之外还有另一层缓存,其形式为System.Web.OutputCacheModule,所有请求都会经过该层。这就像应用程序前面的 HTTP 缓存一样。因此,如果您设置合理的缓存标头而不应用 OutputCacheAttribute,那么您的响应将被缓存在这里。例如:
Response.Cache.SetLastModified(lastModifiedDate);
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetExpires(DateTime.Now + timespan);
根据上述内容,outputcachemodule 将缓存您的内容,并且对同一 URL 的任何请求都将从缓存中提供服务。使用 If-Modified-Since 的请求将收到 304。(您可以同样使用 ETag)。当您的缓存过期时,下一个请求将正常到达您的应用程序,但如果您知道内容没有更改,您可以返回与之前相同的 Last-Modified 或 ETag。一旦缓存了下一个响应,后续客户端将能够延长其缓存生命周期,而无需重新下载内容
尽管此选项降低了不必要的内容下载的可能性,但它并没有消除这种情况 - (服务器)缓存过期后的第一个请求将正常提供服务并导致 200,即使 304 本来是合适的。但这可能是最好的,因为它使缓存能够获取响应正文的新副本,该副本在之前过期时会被丢弃,因此可以直接从缓存提供未来的请求。我相信 HTTP 缓存理论上可以比这更聪明,并使用 304 来延长自己的缓存生命周期,但 ASP.NET 似乎不支持这一点。
(在上面的代码中编辑将 SetMaxAge 替换为 SetExpires - 似乎 IIS/asp.net 不会尊重 max-age 标头,除非您还 SetSlidingExpiration(true) 但该设置似乎阻止了我们想要的缓存)
| 归档时间: |
|
| 查看次数: |
18298 次 |
| 最近记录: |