ASP.NET Core怎么实现输出缓存 Output Caching配置方法

ASP.NET Core 7起内置Output Caching替代[ResponseCache]和IMemoryCache,基于中间件实现、支持策略化与共享缓存,适用于所有HTTP终结点;需在Program.cs中调用AddOutputCaching()和UseOutputCaching(),并可通过[OutputCache]特性或WithMetadata配置缓存策略,支持Duration、VaryByQueryKeys、VaryByHeader等参数,自动设置Cache-Control头,命中时返回X-Output-Cache: Hit。

ASP.NET Core 7 开始内置了 Output Caching(输出缓存),替代了旧版的 [ResponseCache]IMemoryCache 手动缓存响应体的方式,支持更细粒度、可策略化、可共享的 HTTP 级别响应缓存。它基于中间件实现,不依赖控制器或视图,适用于 MVC、Razor Pages、Minimal API 等所有 HTTP 终结点。

启用 Output Caching 中间件

Program.cs 中注册并启用缓存服务和中间件:

  • 调用 builder.Services.AddOutputCaching() 添加服务(支持自定义缓存提供者,如内存、分布式)
  • app.UseOutputCaching() 添加中间件,必须放在 UseRouting 之后、UseEndpointsMap 之前

示例:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOutputCaching(); // 默认使用内存缓存

var app = builder.Build();
app.UseRouting();
app.UseOutputCaching(); // ⚠️ 位置很重要
app.MapControllers();
app.Run();

为 Minimal API 或控制器配置缓存策略

有两种主流方式:声明式(特性)和代码式(委托)。推荐优先使用特性,简洁清晰。

  • 控制器/Action 上加 [OutputCache]:最常用,支持 DurationPolicyNameVaryByQueryKeysVaryByHeader 等参数
  • Minimal API 使用 WithMetadata():例如 app.MapGet("/api/data", () => "hello").WithMetadata(new OutputCacheAttribute { Duration = 60 });
  • 全局策略注册:在 AddOutputCaching() 时通过 .AddPolicy("my-policy", builder => ...) 预定义策略,再用 [OutputCache(PolicyName = "my-policy")] 复用

常见缓存控制场景与写法

输出缓存会自动设置 Cache-Control 响应头,并根据策略决定是否复用响应。注意以下高频需求写法:

  • 缓存 10 分钟[OutputCache(Duration = 600)]
  • 按查询参数区分缓存(如分页):[OutputCache(VaryByQueryKeys = new[] { "page", "size" })]
  • 按请求头区分(如 Accept-Language):[OutputCache(VaryByHeader = "Accept-Language")]
  • 禁用缓存(绕过)[OutputCache(NoStore = true, Duration = 0)](仍会走中间件,但不存储)
  • 仅对匿名用户缓存:需结合 VaryByCustom 或自定义 IOutputCachePolicy 判断 HttpContext.User.Identity.IsAuthenticated

调试与验证缓存是否生效

最直接方式是查看响应头:

  • 命中缓存时,响应含 X-Output-Cache: Hit(开发环境默认开启该标头)
  • 未命中或跳过时,可能是策略不匹配、请求方法非 GET/HEAD、状态码非 2xx/304、或有 Set-Cookie 等禁止缓存的响应头
  • 开发时可启用日志:builder.Logging.AddConsole().AddFilter("Microsoft.AspNetCore.OutputCaching", LogLevel.Debug);

注意:本地开发默认使用内存缓存,无持久性;生产建议搭配 Redis(需引用 Microsoft.Extensions.Caching.StackExchangeRedis 并注册 AddStackExchangeRedisOutputCaching)。

基本上就这些。Output Caching 设计轻量、语义明确,比手动管理 IMemoryCache 更安全,也比旧 [ResponseCache] 更灵活。关键是理解「策略驱动」和「Vary 机制」——缓存不是简单存 Response.Body,而是按一组维度键(key)来索引和匹配。