- 响应缓存在 ASP.NET Core 中的中间件Response Caching Middleware in ASP.NET Core
- 配置Configuration
- 选项Options
- VaryByQueryKeysVaryByQueryKeys
- 响应缓存中间件使用的 HTTP 标头HTTP headers used by Response Caching Middleware
- 缓存遵从请求缓存控制指令Caching respects request Cache-Control directives
- 故障排除Troubleshooting
- 其他资源Additional resources
- 配置Configuration
- 选项Options
- VaryByQueryKeysVaryByQueryKeys
- 响应缓存中间件使用的 HTTP 标头HTTP headers used by Response Caching Middleware
- 缓存遵从请求缓存控制指令Caching respects request Cache-Control directives
- 故障排除Troubleshooting
- 其他资源Additional resources
响应缓存在 ASP.NET Core 中的中间件Response Caching Middleware in ASP.NET Core
本文内容
作者:John Luo
此文章介绍了如何在 ASP.NET Core 应用程序中配置缓存响应的中间件。中间件确定响应何时可缓存、存储响应,并提供来自缓存的响应。有关 HTTP 缓存和[ResponseCache]
属性的介绍,请参阅响应缓存。
配置Configuration
响应缓存中间件可通过共享框架隐式地用于 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();
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();
});
}
示例应用添加标头以在后续请求时控制缓存:
// 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();
});
响应缓存中间件仅缓存服务器响应,导致了200(正常)状态代码。中间件将忽略任何其他响应,包括错误页。
警告
包含经过身份验证的客户端的内容的响应必须标记为不可缓存,以防中间件存储和服务这些响应。有关中间件如何确定响应是否可缓存的详细信息,请参阅缓存的条件。
选项Options
响应缓存选项如下表中所示。
选项 | 说明 |
---|---|
MaximumBodySize | 响应正文的最大可缓存大小(以字节为单位)。默认值为 64 1024 1024 (64 MB)。 |
SizeLimit | 响应缓存中间件的大小限制(以字节为单位)。默认值为 100 1024 1024 (100 MB)。 |
UseCaseSensitivePaths | 确定是否将响应缓存在区分大小写的路径上。默认值是 false 。 |
下面的示例将中间件配置为:
- 大小小于或等于1024字节的缓存响应。
- 将响应存储为区分大小写的路径。例如,
/page1
和/Page1
单独存储。
services.AddResponseCaching(options =>
{
options.MaximumBodySize = 1024;
options.UseCaseSensitivePaths = true;
});
VaryByQueryKeysVaryByQueryKeys
使用 MVC/web API 控制器或 Razor Pages 页面模型时, [ResponseCache]
属性指定为响应缓存设置适当的标头所需的参数。严格需要中间件的 [ResponseCache]
属性的唯一参数 VaryByQueryKeys,这与实际 HTTP 标头不对应。有关详细信息,请参阅 响应缓存在 ASP.NET Core。
如果不使用 [ResponseCache]
属性,响应缓存可能会与 VaryByQueryKeys
不同。直接从HttpContext使用 ResponseCachingFeature:
var responseCachingFeature = context.HttpContext.Features.Get<IResponseCachingFeature>();
if (responseCachingFeature != null)
{
responseCachingFeature.VaryByQueryKeys = new[] { "MyKey" };
}
使用 VaryByQueryKeys
中 *
的单个值将按所有请求查询参数改变缓存。
响应缓存中间件使用的 HTTP 标头HTTP headers used by Response Caching Middleware
下表提供了有关影响响应缓存的 HTTP 标头的信息。
标头 | 详细信息 |
---|---|
Authorization | 如果标头存在,则不会缓存响应。 |
Cache-Control | 中间件仅考虑用 public 缓存指令标记的缓存响应。具有以下参数的控件缓存:- max-age - max-stale† - 最小-新 - must-revalidate - no-cache - 无-商店 - 仅限-缓存 - 专用 - 公共 - s-maxage - proxy-revalidate‡ †如果没有指定 max-stale 的限制,则中间件不会执行任何操作。‡proxy-revalidate 与 must-revalidate 的效果相同。有关详细信息,请参阅RFC 7231:请求缓存控制指令。 |
Pragma | 请求中的 Pragma: no-cache 标头将产生与 Cache-Control: no-cache 相同的效果。如果存在此标头,则由 Cache-Control 标头中的相关指令重写。考虑向后兼容 HTTP/1.0。 |
Set-Cookie | 如果标头存在,则不会缓存响应。请求处理管道中设置一个或多个 cookie 的任何中间件会阻止响应缓存中间件缓存响应(例如,基于 cookie 的 TempData 提供程序)。 |
Vary | Vary 标头用于根据另一个标头改变缓存的响应。例如,通过编码来缓存响应,包括 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 标头。 |
Age | 忽略原始响应中发送的 Age 标头。中间件在为缓存的响应提供服务时计算一个新值。 |
缓存遵从请求缓存控制指令Caching respects request Cache-Control directives
中间件遵循HTTP 1.1 缓存规范的规则。规则要求使用缓存来服从客户端发送的有效 Cache-Control
标头。在规范下,客户端可以使用 no-cache
标头值发出请求,并强制服务器为每个请求生成新的响应。目前,在使用中间件时,不存在对此缓存行为的开发人员控制,因为中间件遵循官方缓存规范。
为了更好地控制缓存行为,将介绍其他缓存功能的 ASP.NET Core。请参阅下列主题:
故障排除Troubleshooting
如果缓存行为与预期不符,请确认响应是可缓存的并且能够通过缓存提供服务。检查请求的传入标头和响应的传出标头。启用日志记录以帮助进行调试。
在对缓存行为进行测试和故障排除时,浏览器可能会以不需要的方式设置影响缓存的请求标头。例如,浏览器可以将 Cache-Control
标题设置为刷新页面时 no-cache
或 max-age=0
。以下工具可以显式设置请求标头,并优先于测试缓存:
缓存条件Conditions for caching
- 请求必须导致服务器响应,状态代码为200(正常)。
- 请求方法必须为 GET 或 HEAD。
- 在
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-age
和s-maxage
缓存指令指定的响应不能过时。- 响应缓冲必须成功。响应的大小必须小于配置的或默认 SizeLimit。响应的正文大小必须小于配置的或默认的 MaximumBodySize。
- 必须根据RFC 7234规范来缓存响应。例如,"请求" 或 "响应" 标头字段中不得存在 "
no-store
" 指令。有关详细信息,请参阅第3部分:将响应存储在RFC 7234的缓存中。
备注
用于生成安全令牌以防止跨站点请求伪造(CSRF)攻击的防伪系统将 Cache-Control
和 Pragma
标头设置为 no-cache
,以便不缓存响应。有关如何为 HTML 窗体元素禁用防伪标记的信息,请参阅 在 ASP.NET Core 防止跨站点请求伪造 (XSRF/CSRF) 攻击。
其他资源Additional resources
- ASP.NET Core 中的应用启动
- ASP.NET Core 中间件
- 缓存在内存中 ASP.NET Core
- ASP.NET Core 中的分布式缓存
- 使用 ASP.NET Core 中的更改令牌检测更改
- 响应缓存在 ASP.NET Core
- ASP.NET Core MVC 中的缓存标记帮助程序
- ASP.NET Core 中的分布式缓存标记帮助程序
此文章介绍了如何在 ASP.NET Core 应用程序中配置缓存响应的中间件。中间件确定响应何时可缓存、存储响应,并提供来自缓存的响应。有关 HTTP 缓存和[ResponseCache]
属性的介绍,请参阅响应缓存。
配置Configuration
使用AspNetCore 元包或添加对AspNetCore. ResponseCaching包的包引用。
在 Startup.ConfigureServices
中,将响应缓存中间件添加到服务集合:
public void ConfigureServices(IServiceCollection services)
{
services.AddResponseCaching();
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
将应用程序配置为将中间件与 UseResponseCaching 扩展方法一起使用,该方法将中间件添加到 Startup.Configure
中的请求处理管道:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
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.UseMvc();
}
示例应用添加标头以在后续请求时控制缓存:
// 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();
});
响应缓存中间件仅缓存服务器响应,导致了200(正常)状态代码。中间件将忽略任何其他响应,包括错误页。
警告
包含经过身份验证的客户端的内容的响应必须标记为不可缓存,以防中间件存储和服务这些响应。有关中间件如何确定响应是否可缓存的详细信息,请参阅缓存的条件。
选项Options
响应缓存选项如下表中所示。
选项 | 说明 |
---|---|
MaximumBodySize | 响应正文的最大可缓存大小(以字节为单位)。默认值为 64 1024 1024 (64 MB)。 |
SizeLimit | 响应缓存中间件的大小限制(以字节为单位)。默认值为 100 1024 1024 (100 MB)。 |
UseCaseSensitivePaths | 确定是否将响应缓存在区分大小写的路径上。默认值是 false 。 |
下面的示例将中间件配置为:
- 大小小于或等于1024字节的缓存响应。
- 将响应存储为区分大小写的路径。例如,
/page1
和/Page1
单独存储。
services.AddResponseCaching(options =>
{
options.MaximumBodySize = 1024;
options.UseCaseSensitivePaths = true;
});
VaryByQueryKeysVaryByQueryKeys
使用 MVC/web API 控制器或 Razor Pages 页面模型时, [ResponseCache]
属性指定为响应缓存设置适当的标头所需的参数。严格需要中间件的 [ResponseCache]
属性的唯一参数 VaryByQueryKeys,这与实际 HTTP 标头不对应。有关详细信息,请参阅 响应缓存在 ASP.NET Core。
如果不使用 [ResponseCache]
属性,响应缓存可能会与 VaryByQueryKeys
不同。直接从HttpContext使用 ResponseCachingFeature:
var responseCachingFeature = context.HttpContext.Features.Get<IResponseCachingFeature>();
if (responseCachingFeature != null)
{
responseCachingFeature.VaryByQueryKeys = new[] { "MyKey" };
}
使用 VaryByQueryKeys
中 *
的单个值将按所有请求查询参数改变缓存。
响应缓存中间件使用的 HTTP 标头HTTP headers used by Response Caching Middleware
下表提供了有关影响响应缓存的 HTTP 标头的信息。
标头 | 详细信息 |
---|---|
Authorization | 如果标头存在,则不会缓存响应。 |
Cache-Control | 中间件仅考虑用 public 缓存指令标记的缓存响应。具有以下参数的控件缓存:- max-age - max-stale† - 最小-新 - must-revalidate - no-cache - 无-商店 - 仅限-缓存 - 专用 - 公共 - s-maxage - proxy-revalidate‡ †如果没有指定 max-stale 的限制,则中间件不会执行任何操作。‡proxy-revalidate 与 must-revalidate 的效果相同。有关详细信息,请参阅RFC 7231:请求缓存控制指令。 |
Pragma | 请求中的 Pragma: no-cache 标头将产生与 Cache-Control: no-cache 相同的效果。如果存在此标头,则由 Cache-Control 标头中的相关指令重写。考虑向后兼容 HTTP/1.0。 |
Set-Cookie | 如果标头存在,则不会缓存响应。请求处理管道中设置一个或多个 cookie 的任何中间件会阻止响应缓存中间件缓存响应(例如,基于 cookie 的 TempData 提供程序)。 |
Vary | Vary 标头用于根据另一个标头改变缓存的响应。例如,通过编码来缓存响应,包括 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 标头。 |
Age | 忽略原始响应中发送的 Age 标头。中间件在为缓存的响应提供服务时计算一个新值。 |
缓存遵从请求缓存控制指令Caching respects request Cache-Control directives
中间件遵循HTTP 1.1 缓存规范的规则。规则要求使用缓存来服从客户端发送的有效 Cache-Control
标头。在规范下,客户端可以使用 no-cache
标头值发出请求,并强制服务器为每个请求生成新的响应。目前,在使用中间件时,不存在对此缓存行为的开发人员控制,因为中间件遵循官方缓存规范。
为了更好地控制缓存行为,将介绍其他缓存功能的 ASP.NET Core。请参阅下列主题:
故障排除Troubleshooting
如果缓存行为与预期不符,请确认响应是可缓存的并且能够通过缓存提供服务。检查请求的传入标头和响应的传出标头。启用日志记录以帮助进行调试。
在对缓存行为进行测试和故障排除时,浏览器可能会以不需要的方式设置影响缓存的请求标头。例如,浏览器可以将 Cache-Control
标题设置为刷新页面时 no-cache
或 max-age=0
。以下工具可以显式设置请求标头,并优先于测试缓存:
缓存条件Conditions for caching
- 请求必须导致服务器响应,状态代码为200(正常)。
- 请求方法必须为 GET 或 HEAD。
- 在
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-age
和s-maxage
缓存指令指定的响应不能过时。- 响应缓冲必须成功。响应的大小必须小于配置的或默认 SizeLimit。响应的正文大小必须小于配置的或默认的 MaximumBodySize。
- 必须根据RFC 7234规范来缓存响应。例如,"请求" 或 "响应" 标头字段中不得存在 "
no-store
" 指令。有关详细信息,请参阅第3部分:将响应存储在RFC 7234的缓存中。
备注
用于生成安全令牌以防止跨站点请求伪造(CSRF)攻击的防伪系统将 Cache-Control
和 Pragma
标头设置为 no-cache
,以便不缓存响应。有关如何为 HTML 窗体元素禁用防伪标记的信息,请参阅 在 ASP.NET Core 防止跨站点请求伪造 (XSRF/CSRF) 攻击。