本文经过介绍了Asp.Net中MVC缓存的种类,以及他们之间的区别等内容,让学习者可以深刻的了解MVC缓存的原理机制,如下是具体内容:html
缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当 web 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝。web
Web应用缓存技术大致上能够分为两类:服务端缓存和客户端缓存。两种目标都是减小重复性内容的生成和网络传输工做,由于缓存数据存储的位置不一样,而分为服务端缓存和客户端缓存。数据库
服务端缓存浏览器
服务端缓存技术关注于服务端数据查询,生成或者操做技术。主要就是减小处理请求的工做量,减小数据库查询次数和生成HTML数据的CPU周期--减小每一个bit的数据。
对于服务端缓存来讲,不论是刷新页面,从新输入地址,仍是Control+F5都不会规避缓存,若是缓存数据有效,必定是请求的缓存数据。缓存
输出缓存(Output Cache)服务器
输出缓存是Asp.Net下最经常使用的缓存机制。输出缓存,缓存服务端生成的HTML数据--缓存Action下返回数据(Html/Json)。这样,在每次调用相同的Action时,就不须要再次执行Action方法。网络
缓存位置(Location)性能
OutputCache
使缓存的内容通常放在三个位置上:服务端,代理服务器,浏览器客户端。经过Loaction
属性能够设置缓存的位置。学习
Loaction
属性有以下值:url
Any Client Downstream Server None ServerAndClient
默认值为Any
,就是在三个位置都会缓存。可是应该根据不一样的状况使用不一样的缓存位置。好比:要缓存的内容是针对特定用户的,每一个用户都会不一样。这样的话,该缓存就不能保存在服务器上。应该保存在浏览器客户端上。
使用Output Cache
在Controller
或者Action
上添加[OutputCache]
特性,使得被添加的Controller
或Action
能够缓存返回的数据。(在Action
添加会缓存当前的Action
,在Controller
会缓存该Controller
下的全部Action
)
以下代码:当第一次方法该Action时,开始计时10秒,此10秒内全部访问该Action的请求都会请求缓存数据。当10秒结束后,再从新开始等待新一次请求,开始新的10秒缓存。就是每隔10秒丢掉旧缓存,等待新的请求,更新缓存数据。
using System.Web.Mvc; using System.Web.UI; namespace MvcApplication1.Controllers { public class HomeController : Controller { //缓存时间10秒,缓存变量为无,缓存位置为服务端 [OutputCache(Duration=10, VaryByParam="none", Location = OutputCacheLocation.Server)] public ActionResult Index() { return View(); } } }
View:
@{ ViewBag.Title = "Index"; } <h2>Index</h2> <p>@DateTime.Now.ToString()</p>
点击F12,查看请求
须要注意的是:
该缓存时间是绝对时间。此缓存是对全部访问该页面的用户都有效。不能保证缓存必定有效。当内存资源不够时,缓存就会自动地将没用的或者优先级低缓存清除。
客户端缓存
除了服务端缓存外,客户端也能够缓存数据。它避免了向服务器重复提交获取重复数据的请求,把一些重复数据缓存到本地。服务端缓存是为了更快的处理客户端请求,而客户端缓存则是为了不没必要要的请求。
(浏览器会自动把静态资源缓存到浏览器)
MVC中指定Location
值为OutputCacheLocation.Client
使缓存在浏览器客户端上。
using System.Web.Mvc; using System.Web.UI; namespace MvcApplication1.Controllers { public class BadUserController : Controller { //缓存时间为10秒,缓存参数为无,缓存位置为客户端 [OutputCache(Duration = 10, VaryByParam = "none",Location = OutputCacheLocation.Client)] public ActionResult ClientCache() { return View(); } } }
@{ ViewBag.Title = "ClientCache"; } <h2>ClientCache</h2> <p>@DateTime.Now.ToString()</p>
客户端缓存和服务端缓存不同。
刷新,从新输入地址,和Control+F5都有可能破坏客户端缓存,从服务端从新获取数据。
浏览器刷新,和从新输入地址会避免请求该URL页面的客户端缓存,只避免请求该URL页面的缓存。(若是该页面有其余URL是被客户端缓存的,这些资源或页面的缓存不会被避免)。
那么什么状况下客户端缓存才有效?
经过URL访问,客户端缓存才有效。
好比:
页面A是客户端缓存,同时页面A有一个跳向页面B的连接。经过A到达页面B,同时页面B也有一个连接,这个连接跳向A。经过B再次访问A,此时页面A获取的数据就是客户端的缓存数据,并无请求服务端,是没有请求服务端。不是304,status-code依然是200。 Status-Code:304/200(from cache)
304
只有当客户端和服务端同时都缓存了数据。且缓存没有更新的时候,才会有304。即这个缓存是要到服务端验证(根据ETag和If-Modify-Since),该缓存是否最新。若是要更新缓存,从服务端获取数据,status code:200,不然status code:304.
304 和200(from cache)区别
304是会到服务端去校验一次当前客户端缓存是否有效(根据ETag和If-Modify-Since)。而200(from cache)则没有向服务端校验,也没有向服务端请求,直接使用了客户端缓存。
有时咱们又须要避免这种没有向服务端请求,直接使用缓存的状况。解决办法就是更改这个缓存的url,添加一个版本号或惟一值。这样由于url的更改使得在客户端没有对应的url缓存,就会从服务端从新获取,再缓存该URL的数据。
不一样内容的输出缓存
以前的缓存都是Action返回相同的内容。若是Action每次返回的内容不一样,那又该怎么缓存这些不一样的内容呢?
使用OutputCache
特性的VaryByParam
属性来解决这个问题。当表单参数或查询字符串参数变化时,该属性可以建立同一个Action下不一样的缓存。
以下代码:Master 获取列表。Details 获取列表中选择项的详细内容。经过使用VaryByParam
来缓存不一样的id
的列表项的详细内容。
using System.Web.Mvc; namespace MvcApplication1.Controllers { public class MoviesController : Controller { public MoviesController() { } [OutputCache(Duration=int.MaxValue, VaryByParam="none")] public ActionResult Master() { //获取列表 return View(); } [OutputCache(Duration = int.MaxValue, VaryByParam = "id")] public ActionResult Details(int id) { //根据参数id,从数据库中获取指定详细内容,并缓存该内容。不一样的id会获得不一样的内容,天然也会有缓存。 //可是若是设置VaryByParam="none"那么无论id是多少,都直接从缓存中获取数据,不执行该Action,这样就会只返回第一次选择项的数据。 return View(); } } }
Details()
操做包括一个带有值“Id”的VaryByParam
属性。当将Id参数的不一样值传递给控制器操做时,将生成不一样的缓存内容。
VaryByParam
能够根据参数缓存不一样的内容
当VaryByParam="*"
: 每当表单或查询字符串参数变化时,建立一个不一样的缓存版本。当VaryByParam="none"
: 不建立不一样的缓存内容,不根据参数缓存不一样的内容,即只有一个内容的缓存。当VaryByParam="参数列表"
: 为不一样的参数建立不一样的缓存版本。
缓存配置
除了在OutputCache
特性上直接配置缓存策略,能够在web.config
文件中使用缓存配置文件,同一管理缓存的策略。使用配置文件相比直接使用属性有以下几点好处:
能够实现一次定义,多处使用。
能够修改web配置文件,而无需从新编译应用程序。(若是想把已经部署到生产环境中的应用程序禁用缓存,能够修改web配置文件中定义的缓存配置。对web配置文件的任何更改都将被自动检测并应用。)
例如,web.config部分定义了一个名为“cache1Hour”的缓存配置文件。使用该配置项时,只需指定CacheProfile=配置项名称便可。
<caching> <outputCacheSettings> <outputCacheProfiles> <add name="Cache1Hour" duration="3600" varyByParam="none"/> </outputCacheProfiles> </outputCacheSettings> </caching>
using System; using System.Web.Mvc; namespace MvcApplication1.Controllers { public class ProfileController : Controller { //配置文件中的缓存策略名称赋值给CacheProfile [OutputCache(CacheProfile="Cache1Hour")] public string Index() { return DateTime.Now.ToString(); } } }
简单介绍下Http缓存的头相关信息:
消息头 | 值 | 类型 | 说明 |
---|---|---|---|
Expires | Thu, 30 Nov 2017 08:21:14 GMT | 响应 | 过时时间,为格林威治时间 (GMT) |
Pragma | no-cache | 响应 | 忽略浏览器缓存(Http1.1用Cache-Control代替) |
Cache-Control | no-cache | 请求/响应 | 客户端缓存验证 |
Cache-Control | no-store | 请求/响应 | 不在任何地方保存数据,不容许被缓存 |
Cache-Control | max-age=[秒] | 请求/响应 | 设置浏览器缓存最长时间 |
Cache-Control | public | 响应 | 缓存在任何地方 |
Cache-Control | private | 响应 | 缓存该用户的浏览器 |
Last-Modified | Thu, 30 Nov 2017 08:21:14 GMT | 响应 | 告诉浏览器服务端最后一次修改的时间 |
If-Modified-Since | Thu, 30 Nov 2017 08:21:14 GMT | 请求 | 若是浏览器中Last-Modofied有值,在请求中把值给If-Modified-Since,提交给服务端 |
ETag | 3df04c15b968d31:0 | 响应 | 该资源及其版本在服务端的惟一标识 |
If-None-Match | 3df04c15b968d31:0 | 请求 | 把上次请求中获取到的ETag值,赋值给If-None-Match并提交给服务端 |
Vary | Accept-Encoding | 响应 | 从多个缓存副本中选择匹配的版本 |
有几个容易理解错误的点
no-cache: 使用no-cache 指令的目的是为了防止从缓存中使用过时的资源,因此每次使用缓存时都要到服务端去验证。从字面意思上很容易把no-cache误解成为不缓存,但事实上no-cache表明不缓存过时的资源,缓存会向源服务器进行有效期确认后处理资源。
no-store: 不存储客户端相关请求或服务器响应的任何内容,即真正的不缓存。