大佬教程收集整理的这篇文章主要介绍了谈谈ASP.NET Core中的ResponseCaching,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
<h2 id="前言">前言
前面的博客谈的大多数都是针对数据的缓存,今天我们来换换口味。来谈谈在ASP.NET Core中的ResponseCaching,与ResponseCaching关联密切的也就是常说的http缓存。
在阅读本文内容之前,默认各位有http缓存相关的基础,主要是Cache-Control相关的。
这里也贴两篇相关的博客:
回到正题,对于ASP.NET Core中的ResponseCaching,本文主要讲三个相关的小内容
这里主要是通过设置http的响应头来完成这件事的。方法主要有两种:
其一,直接用Response对象去设置。
这种方式也有两种写法,@R_801_5913@:
public IActionResult Index() { //直接一,简单粗暴,不要拼写错了就好~~ Response.Headers[Microsoft.Net.http.Headers.HeaderNames.Cachecontrol] = "public,max-age=600";//直接二,略微优雅点 //Response.GetTypedHeaders().Cachecontrol = new Microsoft.Net.http.Headers.CachecontrolHeaderValue() //{ // Public = true,// MaxAge = TimeSpan.FromSeconds(600) //}; return View();
}
这两者效果是一样的,大致如下:
title="谈谈ASP.NET Core中的ResponseCaching" alt="谈谈ASP.NET Core中的ResponseCaching" src="https://cn.js-code.com/res/2019/02-08/23/c2381568901ee39fa61c48f15b59f47c.png">
它们都会给响应头加上 Cache-Control: public,max-age=600
,可能有人会问,加上这个有什么用?
那我们再来看张动图,应该会清晰不少。
title="谈谈ASP.NET Core中的ResponseCaching" alt="谈谈ASP.NET Core中的ResponseCaching" src="https://cn.js-code.com/res/2019/02-08/23/0353d133c58dc2b3f058b786df1b5fd9.gif">
这里事先在代码里面设置了一个断点,正常情况下,只要请求这个action都是会进来的。
但是从上图可以发现,只是第一次才进了断点,其他直接打开的都没有进,而是直接返回结果给我们了,这也就说明缓存起作用了。
同样的,再来看看下面的图,from disk cache
也足以说明,它并没有请求到服务器,而是直接从本地返回的结果。
title="谈谈ASP.NET Core中的ResponseCaching" alt="谈谈ASP.NET Core中的ResponseCaching" src="https://cn.js-code.com/res/2019/02-08/23/cc8ba2e31692f68a552ff6dbf50c7602.png">
在上面的做法中,我们将设置头部信息的代码和业务代码混在一起了,这显然不那么合适。
下面来看看第二种方法,也是比较推荐的方法。
其二,用ResponseCacheAttribute去处理缓存相关的事情。
对于和上面的同等配置,只需要下面这样简单设置一个属性就可以了。
[ResponseCache(Duration = 600)] public IActionResult Index() { return View(); }
效果和上面是一致的!处理起来是不是简单多了。
既然这两种方式都能完成一样的效果,那么ResponseCache这个Attribute本质也是往响应头写了相应的值。
但是我们知道,纯粹的Attribute并不能完成这一操作,其中肯定另有玄机!
翻了一下源码,可以看到它实现了IFilterFactory这个关键的接口。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,AllowMultiple = false,Inherited = truE)] public class ResponseCacheAttribute : Attribute,IFilterFactory,IorderedFilter { public IFilterMetadata CreateInstance(IserviceProvider serviceProvider) { //..return new ResponseCacheFilter(new CacheProfile { Duration = _duration,LOCATIOn = _LOCATIOn,NoStore = _noStore,VaryByHeader = VaryByHeader,VaryByQueryKeys = VaryByQueryKeys,}); }
}
也就是说,真正起作用的是ResponseCacheFilter这个Filter,核心代码如下:
public void OnActionExecuTing(ActionExecuTingContext context) { var headers = context.httpContext.Response.Headers;// Clear all headers headers.Remove(HeaderNames.Vary); headers.Remove(HeaderNames.Cachecontrol); headers.Remove(HeaderNames.Pragma); if (!String.IsNullOrEmpty(VaryByHeader)) { headers[HeaderNames.Vary] = VaryByHeader; } if (NoStorE) { headers[HeaderNames.Cachecontrol] = "no-store"; // Cache-control: no-store,no-cache is valid. if (LOCATIOn == ResponseCacheLOCATIOn.NonE) { headers.AppendCommaSeparatedValues(HeaderNames.Cachecontrol,"no-cache"); headers[HeaderNames.Pragma] = "no-cache"; } } else { headers[HeaderNames.Cachecontrol] = cachecontrolValue; }
}
它的本质自然就是给响应头部写了一些东西。
通过上面的例子已经知道了ResponseCacheAttribute运作的基本原理,下面再来看看如何配置出其他不同的效果。
下面的表格列出了部分常用的设置和生成的响应头信息。
响应头 |
---|
它相当于指定了一个“配置文件”,并在这个“配置文件”中设置了ResponseCache的一些值。
这个时候,只需要在ResponseCacheAttribute上面指定这个“配置文件”的名字就可以了,而不用在给Duration等属性赋值了。
在添加MVC这个中间件的时候就需要把这些“配置文件”准备好!
下面的示例代码添加了两份“配置文件”,其中一份名为default,默认是缓存10分钟,还有一份名为Hourly,默认是缓存一个小时,还有一些其他可选配置也用注释的方式列了出来。
services.AddMvc(options => { options.CacheProfiles.Add("default",new Microsoft.AspNetCore.Mvc.CacheProfile { Duration = 600,// 10 min });options.CacheProfiles.Add("Hourly",new Microsoft.AspNetCore.Mvc.CacheProfile { Duration = 60 * 60,// 1 hour //LOCATIOn = Microsoft.AspNetCore.Mvc.ResponseCacheLOCATIOn.Any,//NoStore = true,//VaryByHeader = "User-Agent",//VaryByQueryKeys = new String[] { "aaa" } });
});
现在“配置文件”已经有了,下面就是使用这些配置了!只需要在Attribute上面指定CacheProfilename的名字就可以了。
@R_801_5913@:
[ResponseCache(CacheProfilename = "default")] public IActionResult Index() { return View(); }
ResponseCacheAttribute中还有一个VaryByQueryKeys的属性,这个属性可以根据不同的查询参数进行缓存!
但是这个属性的使用需要结合下一小节的内容,所以这里就不展开了。
先简单解释一下这里的服务端缓存是什么,对比前面的客户端缓存,它是将东西存放在客户端,要用的时候就直接从客户端去取!
同理,服务端缓存就是将东西存放在服务端,要用的时候就从服务端去取。
需要注意的是,如果服务端的缓存命中了,那么它是直接返回结果的,也是不会去访问Action里面的内容!有点类似代理的感觉。
这个相比客户端缓存有一个好处,在一定时间内,“刷新”页面的时候会从这里的缓存返回结果,而不用再次访问Action去拿结果。
要想启用服务端缓存,需要在管道中去注册这个服务,核心代码就是下面的两句。
public void Configureservices(IserviceCollection services) { services.AddResponseCaching(); }public void Configure(IApplicationBuilder app,IHosTingEnvironment env)
{
app.UseResponseCaching();
}
当然,仅有这两句代码,并不能完成这里提到的服务端缓存。还需要前面客户端缓存的设置,两者结合起来才能起作用。
可以看看下面的效果,
title="谈谈ASP.NET Core中的ResponseCaching" alt="谈谈ASP.NET Core中的ResponseCaching" src="https://cn.js-code.com/res/2019/02-08/23/b824d2a7b5d8790bcf2d0dbd0548a46c.gif">
简单解释一下这张图,
第三次请求响应头部的部分信息如下:
Age: 16
Cache-Control: public,max-age=600
这个Age是在变化的!它就等价于缓存的寿命。
如果启用了日志,也会看到一些比较重要的日记信息。
title="谈谈ASP.NET Core中的ResponseCaching" alt="谈谈ASP.NET Core中的ResponseCaching" src="https://cn.js-code.com/res/2019/02-08/23/890bb4f4601988a3f867e6238c3d3740.png">
在上一小节中,我们还有提到ResponseCacheAttribute中的VaryByQueryKeys这个属性,它需要结合ResponseCaching中间件一起用的,这点在注释中也是可以看到的!
// // SumMary: // Gets or sets the query keys to vary by. // // REMARKs: // Microsoft.AspNetCore.Mvc.ResponseCacheAttribute.VaryByQueryKeys requires the // response cache middleware. public String[] VaryByQueryKeys { get; set; }
举个例子(不一定很合适)来看看,假设现在有一个电影列表页面(),可以通过在URL地址上面加查询参数来决定显示第几页的数据。
如果代码是这样写的,
[ResponseCache(Duration = 600)] public IActionResult List(int page = 0) { return Content(page.ToString()); }
结果就会像下面这样,三次请求,返回的都是页码为0的结果!page参数,压根就没起作用!
GET http://localhost:5001/Home/List HTTP/1.1
Host: localhost:5001
HTTP/1.1 200 OK
Date: Thu,05 Apr 2018 07:38:51 GMT
Content-Type: text/plain; charset=utf-8
Server: Kestrel
Content-Length: 1
Cache-Control: public,max-age=600
0
GET http://localhost:5001/Home/List?page=2 http/1.1
Host: localhost:5001
http/1.1 200 OK
Date: Thu,max-age=600
Age: 5
0
GET http://localhost:5001/Home/List?page=5 http/1.1
Host: localhost:5001
http/1.1 200 OK
Date: Thu,max-age=600
Age: 8
0
正确的做法应该是要指定VaryByQueryKeys,如下所示:
[ResponseCache(Duration = 600,VaryByQueryKeys = new String[] { "page" })] public IActionResult List(int page = 0) { return Content(page.ToString()); }
这个时候的结果就是和预期的一样了,不同参数都有对应的结果并且这些数据都缓存了起来。
GET http://localhost:5001/Home/List http/1.1
Host: localhost:5001
http/1.1 200 OK
Date: Thu,05 Apr 2018 07:45:13 GMT
Content-Type: text/plain; charset=utf-8
Server: Kestrel
Content-Length: 1
Cache-Control: public,05 Apr 2018 07:45:22 GMT
Content-Type: text/plain; charset=utf-8
Server: Kestrel
Content-Length: 1
Cache-Control: public,max-age=600
2
GET http://localhost:5001/Home/List?page=5 http/1.1
Host: localhost:5001
http/1.1 200 OK
Date: Thu,05 Apr 2018 07:45:27 GMT
Content-Type: text/plain; charset=utf-8
Server: Kestrel
Content-Length: 1
Cache-Control: public,max-age=600
5
ResponseCachingMiddleware在这里是用了MemoryCache来读写缓存数据的。如果应用重启了,缓存的数据就会失效,要重新来过。
对于一些常年不变或比较少变的js,css等静态文件,也可以把它们缓存起来,避免让它们总是发起请求到服务器,而且这些静态文件可以缓存更长的时间!
如果已经使用了CDN,这一小节的内容就可以暂且忽略掉了。。。
对于静态文件,.NET Core有一个单独的StaticFiles中间件,如果想要对它做一些处理,同样需要在管道中进行注册。
UseStaticFiles
有几个重载方法,这里用的是带StaticFiLeoptions参数的那个方法。
因为StaticFiLeoptions里面有一个OnPrepareResponse可以让我们修改响应头,以达到http缓存的效果。
// // SumMary: // Called after the status code and headers have been set,but before the body has // been written. This can be used to add or change the response headers. public ActionOnPrepareResponse { get; set; }
下面来看个简单的例子:
app.UseStaticFiles(new StaticFiLeoptions { OnPrepareResponse = context => { context.Context.Response.GetTypedHeaders().Cachecontrol = new Microsoft.Net.http.Headers.CachecontrolHeaderValue { Public = true,//for 1 year MaxAge = System.TimeSpan.FromDays(365) }; } });
此时的效果如下:
title="谈谈ASP.NET Core中的ResponseCaching" alt="谈谈ASP.NET Core中的ResponseCaching" src="https://cn.js-code.com/res/2019/02-08/23/73a675313a5dfd84663b5aed8e547846.png">
其一,ResponseCaching中间件对下面的情况是不会进行缓存操作的!
其二,当我们使用了Antiforgery的时候也要特别的注意!!它会直接把响应头部的Cache-Control和Pragma重置成no-cache。换句话说,这两者是水火不容的!
////// Sets the 'Cache-Control' header to 'no-cache,no-store' and 'Pragma' header to 'no-cache' overriding any user set value. /// /// protected virtual void SetDoNotCacheHeaders(HttpContext httpContext) { // Since antifogery token generation is not very obvious to the end users (ex: MVC's form tag generates them // by default),log a warning to let users know of the change in behavior to any cache headers they might // have set explicitly. LogCacheHeaderOverrideWarning(httpContext.Response);httpContext.Response.Headers[HeaderNames.CacheControl] = "no-cache,no-store"; httpContext.Response.Headers[HeaderNames.Pragma] = "no-cache";
}
当然,在某个页面用到了Antiforgery的时候,也该避免在这个页面使用HTTP缓存!
它会在form表单中生成一个隐藏域,并且隐藏域的值是一个生成的token ,难道还想连这个一起缓存?
在.NET Core中用ResponseCaching还是比较简单的,虽然还有一些值得注意的地方,但是并不影响我们的正常使用。
当然,最重要的还是合理使用!仅在需要的地方使用!
最后附上文中Demo的地址
以上是大佬教程为你收集整理的谈谈ASP.NET Core中的ResponseCaching全部内容,希望文章能够帮你解决谈谈ASP.NET Core中的ResponseCaching所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。