ASP.NET Core 中的响应缓存中间件

本文介绍如何在 ASP.NET Core 应用程序中配置响应缓存中间件。 中间件确定响应何时可缓存、存储响应,并提供来自缓存的响应。 有关 HTTP 缓存和属性的介绍 [ResponseCache] ,请参阅响应缓存。

配置

响应缓存中间件可通过共享框架隐式地用于 ASP.NET Core 应用。
Startup.ConfigureServices中 ,将响应缓存中间件添加到服务集合中:

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCaching();
    services.AddRazorPages();
}

使用UseResponseCaching扩展方法将应用程序配置为使用中间件,该方法将中间件添加到Startup.Configure中的请求处理管道中。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseStaticFiles();
    app.UseRouting();
    // UseCors must be called before UseResponseCaching
    // app.UseCors("myAllowSpecificOrigins");

    app.UseResponseCaching();

    app.Use(async (context, next) =>
    {
        context.Response.GetTypedHeaders().CacheControl = 
            new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
            {
                Public = true,
                MaxAge = TimeSpan.FromSeconds(10)
            };
        context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] = 
            new string[] { "Accept-Encoding" };

        await next();
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

警告
使用CORS中间件时,必须在UseResponseCaching之前调用UseCors

该示例应用程序添加了标头来控制后续请求的缓存:

  • Cache-Control:最多可缓存10秒钟的可缓存响应。
  • Vary:仅在后续请求的Accept-Encoding标头与原始请求的标头匹配时,才将中间件配置为提供缓存的响应。
// using Microsoft.AspNetCore.Http;

app.Use(async (context, next) =>
{
    context.Response.GetTypedHeaders().CacheControl = 
        new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
        {
            Public = true,
            MaxAge = TimeSpan.FromSeconds(10)
        };
    context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] = 
        new string[] { "Accept-Encoding" };

    await next();
});

前面的标头不会写入响应,并且在控制器,操作或Razor时被覆盖:

  • 具有[ResponseCache]属性。 即使未设置属性也是如此。 例如,省略VaryByHeader属性将导致从响应中删除相应的标头。

响应缓存中间件仅缓存服务器响应,导致了200(正常)状态代码。 中间件将忽略任何其他响应,包括错误页。

警告

包含经过身份验证的客户端的内容的响应必须标记为不可缓存,以防中间件存储和服务这些响应。
有关中间件如何确定响应是否可缓存的详细信息,请参阅缓存的条件。

选项

响应缓存选项如下表中所示

选项
选项说明
MaximumBodySize响应正文的最大可缓存大小(以字节为单位)。 默认值为 64 * 1024 * 1024 (64 MB)。
SizeLimit响应缓存中间件的大小限制(以字节为单位)。 默认值为 100 * 1024 * 1024 (100 MB)。
UseCaseSensitivePaths确定是否将响应缓存在区分大小写的路径上。 默认值为 false。

以下示例将中间件配置为:

  • 缓存正文大小小于或等于1,024字节的响应。
  • 通过区分大小写的路径存储响应。 例如,/page1/Page1分别存储。
services.AddResponseCaching(options =>
{
    options.MaximumBodySize = 1024;
    options.UseCaseSensitivePaths = true;
});

VaryByQueryKeys

使用MVC/Web API控制器或Razor Pages页面模型时,[ResponseCache]属性指定设置适当的响应缓存标头所需的参数。严格要求中间件使用的[ResponseCache]属性的唯一参数是VaryByQueryKeys,它不对应于实际的HTTP标头。 有关更多信息,请参见ASP.NET Core中的响应缓存。

不使用[ResponseCache]属性时,可以使用VaryByQueryKeys更改响应缓存。 直接从HttpContext.Features使用ResponseCachingFeature

var responseCachingFeature = context.HttpContext.Features.Get<IResponseCachingFeature>();

if (responseCachingFeature != null)
{
    responseCachingFeature.VaryByQueryKeys = new[] { "MyKey" };
}

VaryByQueryKeys中使用等于*的单个值会根据所有请求查询参数来改变缓存。

响应缓存中间件使用的 HTTP 标头

下表提供了有关影响响应缓存的 HTTP 标头的信息。

Header详细信息
Authorization如果标头存在,则不会缓存响应。
Cache-Control中间件仅考虑标记有public cache指令的缓存响应。 使用以下参数控制缓存:
max-age
max-stale†
min-fresh
must-revalidate
no-cache
no-store
only-if-cached
private
public
s-maxage
proxy-revalidate‡
如果没有为max-stale指定任何限制,则中间件不采取任何措施。
proxy-revalidatemust-revalidate 具有相同的效果。
有关详细信息,请参阅RFC 7231:请求缓存控制指令
PragmaPragma: no-cache请求中的标头将产生与相同的效果 Cache-Control: no-cache 。 标头中的相关指令 Cache-Control (如果存在)将重写此标头。 考虑向后兼容 HTTP/1.0
Set-Cookie如果标头存在,则不会缓存响应。 请求处理管道中设置一个或多个 cookie 的任何中间件会阻止响应缓存中间件缓存响应(例如,基于 cookie 的 TempData 提供程序)。
VaryVary标头用于根据另一个标头改变缓存的响应。 例如,通过包含标头来缓存响应, Vary: Accept-Encoding 此标头将使用标头和单独的请求来缓存响应 Accept-Encoding: gzip Accept-Encoding: text/plain 。 永远不会存储标头值 * 为的响应。
Expires除非由其他标头重写,否则不会存储或检索此标头过时的响应 Cache-Control
If-None-Match如果值不为 * ,并且响应的与提供的任何值都不匹配,则将从缓存中提供完整响应 ETag 。 否则,将提供304(未修改)响应。
If-Modified-Since如果 If-None-Match 标头不存在,则在缓存的响应日期比提供的值更新时,将从缓存中提供完整响应。 否则,将提供304-未修改响应。
Date从缓存提供时, Date 如果未在原始响应中提供标头,中间件将设置标头。
Content-Length从缓存提供时, Content-Length 如果未在原始响应中提供标头,中间件将设置标头。
AgeAge忽略原始响应中发送的标头。 中间件在为缓存的响应提供服务时计算一个新值。

缓存遵从请求缓存控制指令

中间件遵守HTTP 1.1缓存规范的规则。 规则需要缓存来兑现客户端发送的有效Cache-Control标头。 根据该规范,客户端可以使用no-cache标头值发出请求,并强制服务器为每个请求生成新的响应。 当前,使用中间件时,开发人员无法控制这种缓存行为,因为中间件遵守官方缓存规范。

若要更好地控制缓存行为,请探索ASP.NET Core的其他缓存功能。 请参阅以下主题:

  • ASP.NET Core 中的缓存内存
  • ASP.NET Core 中的分布式缓存
  • ASP.NET Core MVC 中的缓存标记帮助程序
  • ASP.NET Core 中的分布式缓存标记帮助程序

疑难解答

如果缓存行为与预期的不同,请确认响应是可缓存的并且能够从缓存中得到响应。 检查请求的传入标头和响应的传出标头。 启用日志记录以帮助调试。

在对缓存行为进行测试和故障排除时,浏览器可能会设置以不希望的方式影响缓存的请求标头。 例如,当刷新页面时,浏览器可以将Cache-Control标头设置为no-cachemax-age = 0。 以下工具可以显式设置请求标头,并且是测试缓存的首选工具:

  • Fiddler
  • Postman

缓存条件

  • 请求必须导致服务器响应,状态代码为200(正常)。
  • 请求方法必须为 GETHEAD
  • Startup.Configure中,必须将响应缓存中间件置于需要缓存的中间件之前。 有关详细信息,请参阅ASP.NET Core中间件
  • Authorization标头不得存在。
  • Cache-Control标头参数必须是有效的,并且响应必须标记 public 且未标记 private
  • 如果不存在Cache-Control标头,则必须不存在Pragma:no-cache标头,因为Cache-Control标头在存在时会覆盖Pragma标头。
  • Set-Cookie标题不得存在。
  • Vary标头参数必须有效并且不等于 *
  • Content-Length标头值(如果已设置)必须与响应正文的大小匹配。
  • IHttpSendFileFeature不使用。
  • 响应必须不过期,如Expires标头以及max-ages-maxage缓存指令所指定。
  • 响应缓冲必须成功。 响应的大小必须小于配置的或默认值 SizeLimit 。 响应的正文大小必须小于配置的或默认值
    MaximumBodySize
  • 必须根据RFC 7234规范来缓存响应。 例如, no-store 指令在请求或响应标头字段中不得存在。
    有关详细信息,请参见第3节:在RFC 7234的缓存中存储响应。

备注

用于生成安全令牌以防止跨站点请求伪造(CSRF)攻击的防伪系统将Cache-ControlPragma标头设置为no-cache,这样就不会缓存响应。 有关如何为HTML表单元素禁用防伪令牌的信息,请参见阻止跨站点请求伪造(XSRF / CSRF)攻击ASP.NET Core

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值