asp.net core 中的响应缓存 记录。
什么是缓存,即指那些程序中经常要使用的数据,为了能够快速调用,将其保存在某些快速反应的介质中(如内存、数据库、硬盘)中的数据,这样可以做到避免重复生成实例,以减少开销,提升效率。
在asp.net core中,可以使用分布式缓存或者内存缓存,但这些仅仅是单纯的对数据进行保存。而响应缓存确实对缓存的应用。
响应缓存
HTTP规范写的缓存只针对方法为Get的请求或者HEAD的请求,这样的请求旨在获取URL所指向的资源。如果将资源提供者和缓存消费者称为原始服务器与客户的,那么所谓的缓存则是存在于这两者之间的一个部件。
缓存会根据一定的规则在本地存储一份原始服务器提供的响应副本,保质期内的副本可以直接用来作为后续匹配请求的响应,所以缓存能够避免客户端于原始服务器之间不必要的网络交互。即使过了包支持,缓存也不会直接从原始服务器中获得最新的响应副本,而是向服务器发送一个请求来验证目前的副本是否与最新的内容一致,如果原始服务器做出“一致”的答复,原本过期的响应副本又变得新鲜,并且保证被继续使用。所以,缓存还能避免冗余资源在网络中的重复传输。
详解HTTP缓存
asp.net core 中的响应缓存
使用:
[ResponseCache(Duration = 30, Location = ResponseCacheLocation.Any, NoStore = false, VaryByQueryKeys = new string[] { "id" })] public IActionResult Index(int id) { _logger.LogInformation($"{nameof(Index)} URL:{this.Request.GetDisplayUrl()} 没有使用响应缓存 {DateTime.Now}"); return View(); }
如以上代码所示,将响应缓存的有效期设置为30秒,位置为any(服务器和客户端),其中标识使用了Id。
我们测试如下:
在缓存有效期内,对同一个url进行访问,服务器只处理了一次。
那么上面的VaryByQueryKeys有什么用呢(其实还有VaryByHeader这个属性)?
这个属性主要用来生成缓存键,因为作为资源唯一标识的url并不能唯一标识缓存的响应副本。比如请求URL为https://localhost:5001/Home/Index/1,但是浏览器1要求使用Accept-Encoding:Gzip,而浏览器要求br,假设没有使用VaryByHeader属性,那么将浏览器2,将会收到gzip的编码,很可能导致乱码的情况。
VaryByQueryKeys和VaryByHeader属性
VVVVVVVTL1JOLHACCEPT-ENCODING=gzip, deflate, br 采用VaryByHeader生成的缓存键。
GETHTTPSLOCALHOST:5001/WEATHERFORECAST 没有采用VaryByHeader的缓存键
VVVVVVV699S90HACCEPT-ENCODING=gzip, deflate, brQID=6 采用Id的缓存键。
VVVVVVU3ASKM8HACCEPT-ENCODING=gzip, deflate, br 没有采用Id的缓存键。
由此可见VaryByQueryKeys和VaryByHeader属性非常重要。
asp.net core 实现响应缓存中间件原理
asp.net core中,响应缓存由ResponseCachingMiddleware中间件完成,依照Http1.1的标准,
这个中间件中三个重要的接口
IResponseCachingPolicyProvide 缓存策列提供者接口,接口提供了5个方法,需要满足条件为true才会进入到生成缓存键中
IResponseCachingKeyProvide 缓存键生成接口,处理了如VaryByQueryKeys和VaryByHeader等特性
IResponseCache 响应缓存的缓存操作。
整个流程不算复杂,但是遗憾的是,自带的响应缓存只支持内存缓存,并且对其他缓存位置的支持直接堵死了,IResponseCache接口属于internal保护级。并ResponseCachingMiddleware构造函数直接也是internal。如果想要支持分布式缓存,应该是自己实现响应缓存中间件了。
。 public ResponseCachingMiddleware( RequestDelegate next, IOptions<ResponseCachingOptions> options, ILoggerFactory loggerFactory, ObjectPoolProvider poolProvider) : this( next, options, loggerFactory, new ResponseCachingPolicyProvider(), new MemoryResponseCache(new MemoryCache(new MemoryCacheOptions { SizeLimit = options.Value.SizeLimit })), new ResponseCachingKeyProvider(poolProvider, options)) { } // for testing internal ResponseCachingMiddleware( RequestDelegate next, IOptions<ResponseCachingOptions> options, ILoggerFactory loggerFactory, IResponseCachingPolicyProvider policyProvider, IResponseCache cache, IResponseCachingKeyProvider keyProvider) {