Ultimate ASP.NET CORE 6.0 Web API --- 读书笔记(25)
25 Caching
本文内容来自书籍: Marinko Spasojevic - Ultimate ASP.NET Core Web API - From Zero To Six-Figure Backend Developer (2nd edition)
需要本书和源码的小伙伴可以留下邮箱,有空看到会发送的
缓存可以提高很多系统的性能,但同时,也会出现一些bug。这里会使用到HTTP Cache
API中的缓存的主要目标是,减少客户端向API发送请求的次数,在其他情况下返回完整的响应
为了缩减请求的次数,caching使用过期机制expiration mechanism
此外,为了消除发送完整响应的需要,缓存使用验证机制validation mechanism,这减少了网络带宽。
Cache是一个独立的组件,用来接收API消费者的请求,同时也会接收API的响应,并且将可以作为缓存的响应存起来,一旦响应存起来,如果有消费者请求了相同的API资源,那么缓存中响应就会起作用
cache的行为会因为缓存的类型不同而不同
25.1.1 Cache Types
- Client Cache,是存在于客户端(浏览器)的缓存,这是私有的缓存,每个客户端有自己的缓存
- Gateway Cache,是存在于服务端,这是共享的缓存,所有客户端共享的缓存
- Proxy Cache,存在于
network的缓存,也是共享的缓存
25.1.2 Response Cache Attribute
缓存资源之前,我们需要知道资源是否可以缓存,而响应头可以帮助我们做到,而使用最多的是Cache-Control: max-age=180
它表明,这个响应可以被缓存180秒,当然了,这只是一个响应头,如果需要存储什么,还需要一个cache-store,而在ASP.NET Core提供了一个响应缓存中间件
25.2 Adding Cache Headers
首先在需要缓存的action中,添加特性标记[ResponseCache(Duration = 60)],然后在响应头中就可以看到Cache-Control:public,max-age=60
25.3 Adding Cache-Store
首先是注册缓存的服务
public static void ConfigureResponseCaching(this IServiceCollection services) => services.AddResponseCaching();
builder.Services.ConfigureResponseCaching();
app.UseResponseCaching();
注册之后,就可以使用缓存了,在第一次发送请求之后,会发现出现了缓存的响应头,如果这时候发送第二次请求,会发现,响应头中,除了有缓存的标记,还有一个Age:9的标记,说明了这个资源的已经缓存时间
缓存生效了,但是进一步思考,会发现我们的ResponseCacheAttribute里面有很多可配置的属性,如果将这些属性都配置在了标记上,控制器的代码阅读会变差,所以我们需要将配置抽取出来,用一个名字代替它,这个叫CacheProfiles
同样的,在AddControllers里面,可以配置
builder.Services.AddControllers(config =>
{
config.RespectBrowserAcceptHeader = true;
config.ReturnHttpNotAcceptable = true;
config.InputFormatters.Insert(0, GetJsonPatchInputFormatter());
config.CacheProfiles.Add("120SecondsDuration", new CacheProfile { Duration =
120 });
})...
[ResponseCache(CacheProfileName = "120SecondsDuration")]
这样,在缓存的配置项比较多的时候,就可以将配置抽取出来,这样更多的地方也不需要重复编写配置了
25.4 Expiration Model
Expiration Model允许服务端识别出来响应是否过期


直到这里,如果在客户端上也有缓存,那么请求到这里就会停止了,因为在缓存有效期间,客户端不需要对同一个API做请求了,但是如果是一个共享的缓存,那么另一个客户端请求同一个API的时候,可以看到返回的也是这个缓存,但是Age已经变大了
25.5 Validation Model
Validation Model是用来验证响应的新鲜程度,或者说,检查这个缓存是不是可以被继续使用
让我们假设一种情况,一个共享的缓存,缓存了一个API的结果30分钟,然后某个客户端在5分钟之后更新了这个API的结果,那么如果没有验证机制,那么使用这个API的客户端将会获得错误的响应,这种情况会持续25分钟,直到缓存失效
所以我们需要一个validators。而HTTP标准建议如果可以的话,结合使用Last-Modified和ETag


在第一次请求时,没有缓存,那么请求会穿过缓存到达API,然后响应结果里面,会携带Last-Modified和ETag,然后,第二次请求中,经过缓存的时候,缓存不知道这个资源是不是有效的,所以会向API询问(ETag对应if-None-Match,Last-Modified对应if-Modified-Since)缓存的资源是否有效,如果有效则返回缓存
25.6 Supporting Validation
支持这种validation,我们需要安装新的包Marvin.Cache.Headers在Presentation
这个包支持HTTP缓存头,比如Cache-Control、Expires,Etag、Last-Modified,同时也有实现validation和expiration models
同样的,首先需要配置主项目的服务注册
public static void ConfigureHttpCacheHeaders(this IServiceCollection services) => services.AddHttpCacheHeaders();
builder.Services.ConfigureHttpCacheHeaders();
app.UseHttpCacheHeaders();
然后,需要将我们之前添加的ResponseCacheAttribute去掉,因为上面安装的包会提供这些功能
然后尝试一个请求,可以看到,我们需要的头信息,都生成了,默认的保质期是60秒
{
"Cache-Control": "public,max-age=60",
"ETag": "adadasdasdsadsad",
"Expires": "时间",
"Last-Modified": "时间",
"Age": "9"
}
如果需要对保质期和验证的头部信息做配置,那就可以在服务注册的方法中,进行配置
public static void ConfigureHttpCacheHeaders(this IServiceCollection services) => services.AddHttpCacheHeaders(
expirationOpt =>
{
expirationOpt.MaxAge = 65;
expirationOpt.CacheLocation = CacheLocation.Private;
},
validationOpt => validationOpt.MustRevalidate = true
);
这样配置之后,在响应头中,会发现有变化
{
"Cache-Control": "private,max-age=65,must-revalidate"
}
如果这些全局配置不满足使用,我们需要更加细致的对缓存配置,从global到controller到action,一层层细化,而且内层配置会覆盖外层配置
对controller和action的配置方式是使用Attribute
[HttpCacheExpiration(CacheLocation = CacheLocation.Public, MaxAge = 60)]
[HttpCacheValidation(MustRevalidate = false)]
25.7 Using ETag and Validation
在ResponseCaching中,也就是我们的服务端的缓存存储包,并没有正确地实现Validation Model,需要其他的包来辅助实现中这个功能,但是实现起来并不容易

浙公网安备 33010602011771号