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-ModifiedETag


在第一次请求时,没有缓存,那么请求会穿过缓存到达API,然后响应结果里面,会携带Last-ModifiedETag,然后,第二次请求中,经过缓存的时候,缓存不知道这个资源是不是有效的,所以会向API询问(ETag对应if-None-MatchLast-Modified对应if-Modified-Since)缓存的资源是否有效,如果有效则返回缓存

25.6 Supporting Validation

支持这种validation,我们需要安装新的包Marvin.Cache.HeadersPresentation

这个包支持HTTP缓存头,比如Cache-ControlExpiresEtagLast-Modified,同时也有实现validationexpiration 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"
}

如果这些全局配置不满足使用,我们需要更加细致的对缓存配置,从globalcontrolleraction,一层层细化,而且内层配置会覆盖外层配置

controlleraction的配置方式是使用Attribute

[HttpCacheExpiration(CacheLocation = CacheLocation.Public, MaxAge = 60)]
[HttpCacheValidation(MustRevalidate = false)]

25.7 Using ETag and Validation

ResponseCaching中,也就是我们的服务端的缓存存储包,并没有正确地实现Validation Model,需要其他的包来辅助实现中这个功能,但是实现起来并不容易

posted @   huang1993  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示