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
,需要其他的包来辅助实现中这个功能,但是实现起来并不容易
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?