ASP.Net Core 2.0 - ResponseCaching 中间件 - 不在服务器上缓存
ASP.Net Core 2.0 - ResponseCaching Middleware - Not Caching on Server
我想在 asp.net 核心 2.0 中使用 server-side 响应缓存(输出缓存),发现 Response Caching Middleware 并想尝试使用全新的 asp.coremvc 项目。
这是上面 link 的描述,这让我觉得这可以像输出缓存一样使用。
The middleware determines when responses are cacheable, stores responses, and serves responses from cache.
这是我的 startup.cs 的样子。
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddResponseCaching();
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseResponseCaching();
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
这里是 HomeController.cs
[ResponseCache(Duration = 60)]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
return View();
}
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
_Layout.cshtml 文件底部还有一个时间戳,这样我就可以知道页面何时呈现,如下所示。
<p>© 2018 - ResponseCachingMiddleware - @DateTime.UtcNow</p>
Cache-Control headers 似乎没问题,这是我在加载页面时在 headers 中得到的结果,但时间戳每秒在每次刷新时不断更新。
Cache-Control:public,max-age=60
我从 MS 文档中了解到,响应缓存中间件是 server-side 负责缓存响应的缓存机制,而 Response Caching 似乎只是一个操作响应的过滤器 headers 用于缓存。
不知道我的理解或代码是否有问题,我想抱怨自从我开始使用 ASP.Net Core 进行原型设计以来,我经常有这种感觉。也许您还可以建议更好的资源作为副主题。
我之前看过这个 post
也检查了这一点,但似乎唯一的区别是我使用的是 mvc。
https://github.com/aspnet/ResponseCaching/blob/dev/samples/ResponseCachingSample/Startup.cs
谢谢
编辑:我在输出 window 中看到下面的消息,在 google 上找不到任何关于它的信息,除了我已经检查过响应缓存中间件的几个地方。
Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware:Information:
The response could not be cached for this request.
注意:我希望我可以创建#response-caching-middleware 标签。不确定#responsecache 是否相关。
如果 Cache-Control
header 正在通过,那么它正在运行。从那个角度来看,这就是服务器所能做的。客户端最终决定是否 实际上 缓存资源。发送 header 不会强制客户端做任何事情;事实上,一般情况下,服务器不能强制客户端做任何事情。
我最近也有同样的困惑。
ASP.Net Core 的 ResponseCaching 确实提供 client-side 缓存(通过 HTTP 响应 headers)和 server-side(通过 [=47 的内存缓存中间件) =] 其他中间件,如果响应在缓存中)。 server-side 部分读取 HTTP 响应缓存 headers 以确定它是否应该执行 server-side 缓存(类似于 ISP 或 CDN 可能执行的操作)。
不幸的是,调试 server-side ResponseCaching 很棘手,因为它有奇怪的规则并且没有足够的日志记录。在我的例子中,我下载了微软的源代码来逐步检查它并找到我的代码的问题。
您在输出 window "The response could not be cached for this request" 中找到的注释是一个线索。
请求的 server-side 缓存分为两部分。服务器必须在第一次请求 url 时启动缓存。它将在第二次请求时提供缓存版本。请注意错误消息何时出现,是在第一次还是第二次请求时。这会告诉您它是否无法存储在缓存中,或者是否无法从缓存中检索。
存储和检索的规则都在这个源代码文件中:
https://github.com/aspnet/ResponseCaching/blob/3bf5f6a1ce69b65c998d6f5c739822a9bed4a67e/src/Microsoft.AspNetCore.ResponseCaching/Internal/ResponseCachingPolicyProvider.cs
您的 "Cache-Control:public,max-age=60" header 应该完全符合这些规则。
我的猜测是您确实可以使用它,但不知道如何正确测试它。
此问题中记录了 ResponseCaching 的 counter-intuitive 部分:https://github.com/aspnet/Home/issues/2607
本质上,如果浏览器发送 no-cache 或 no-store header(当您按下 CTRL+F5 或打开调试器工具时),ASP.Net Core 的 ResponseCaching 将响应浏览器的请求& re-generate 响应。
因此,为了测试您的代码是否正常工作,您可能加载了页面,这会启动缓存,然后按 CTRL+F5 到 force-refresh 您的浏览器并且您希望 server-side 响应使用缓存条目而不是 运行 您的 WebAPI 代码。但是,它尊重 no-cache 请求 header 并绕过缓存(并在输出日志中写入该消息)。
测试此方法的方法是清除浏览器缓存 in-between 请求(或切换到隐身模式),而不是使用 CTRL+F5。
附带说明一下,尊重 no-cache/no-store 请求 headers 可能是一个糟糕的设计选择,因为 ASP.Net Core 的 ResponseCache 很可能会被拥有响应的服务器使用,而不是像 CDN/ISP 这样的中间缓存。我已经扩展了基础 ResponseCache,并提供了一个选项来禁用对这些 header 的支持(以及将缓存序列化到磁盘,而不是仅 in-memory)。这是默认缓存的简单 drop-in 替换。
你可以在这里找到我的分机:
https://github.com/speige/AspNetCore.ResponseCaching.Extensions
https://www.nuget.org/packages/AspNetCore.ResponseCaching.Extensions
ResponseCaching 还存在其他一些需要注意的陷阱,您可能已经在您发布的博客 url 中读到过这些内容。 set-cookie 的经过身份验证的请求和响应不会被缓存。只有使用 GET 或 HEAD 方法的请求才会被缓存。如果 QueryString 不同,它将创建一个新的缓存条目。此外,如果请求的某些条件与 previously-cached 请求不同(例如:user-agent、accept-encoding,通常您需要 "Vary" header 来防止缓存, ETC)。最后,如果中间件处理请求,它将 short-circuit 稍后的中间件。确保您的 app.UseResponseCaching() 在 app.UseMVC()
之前注册
我遇到了同样的问题,我正想着急呢,我设置了 app.UseResponseCaching();
以及 services.AddResponseCaching();
并在我的操作之上添加了 ResponseCache
与 Microsoft 官方文档中所说的完全一样,尽管 cache-controll
header 已在从服务器返回的响应中正确设置,但仍然没有缓存在 server-side.
在这个问题上费了几个小时之后,我弄清楚了问题出在哪里以及为什么没有缓存在服务器上。
浏览器默认将请求的 cache-controll
值设置为 max-age=0
(如果请求不是由返回或转发引起的)即使您在响应中正确设置了 cache-controller
在您的操作(或控制器)上添加 ResponseCache
属性,因为请求发送的 cache-controller
设置为 max-age=0
,服务器无法缓存响应,我认为这必须添加到响应缓存限制列表
无论如何,您可以通过在调用 app.UseResponseCaching();
之前添加几行代码来覆盖浏览器的默认行为,另一方面,您需要添加自定义 middle-ware 来修改请求 cache-control
header 调用前的值 app.UseResponseCaching();
.
查看下面的代码,对我有用希望对你也有用
app.Use(async (ctx, next) =>
{
ctx.Request.GetTypedHeaders().CacheControl = new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(60)
};
await next();
}
);
app.UseResponseCaching();
为了确保 ResponseCaching 按预期工作,您也可以使用邮递员,但您必须将 'Send no-cache Header'设置,见下图
我想在 asp.net 核心 2.0 中使用 server-side 响应缓存(输出缓存),发现 Response Caching Middleware 并想尝试使用全新的 asp.coremvc 项目。
这是上面 link 的描述,这让我觉得这可以像输出缓存一样使用。
The middleware determines when responses are cacheable, stores responses, and serves responses from cache.
这是我的 startup.cs 的样子。
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddResponseCaching();
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseResponseCaching();
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
这里是 HomeController.cs
[ResponseCache(Duration = 60)]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
return View();
}
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
_Layout.cshtml 文件底部还有一个时间戳,这样我就可以知道页面何时呈现,如下所示。
<p>© 2018 - ResponseCachingMiddleware - @DateTime.UtcNow</p>
Cache-Control headers 似乎没问题,这是我在加载页面时在 headers 中得到的结果,但时间戳每秒在每次刷新时不断更新。
Cache-Control:public,max-age=60
我从 MS 文档中了解到,响应缓存中间件是 server-side 负责缓存响应的缓存机制,而 Response Caching 似乎只是一个操作响应的过滤器 headers 用于缓存。
不知道我的理解或代码是否有问题,我想抱怨自从我开始使用 ASP.Net Core 进行原型设计以来,我经常有这种感觉。也许您还可以建议更好的资源作为副主题。
我之前看过这个 post
也检查了这一点,但似乎唯一的区别是我使用的是 mvc。 https://github.com/aspnet/ResponseCaching/blob/dev/samples/ResponseCachingSample/Startup.cs
谢谢
编辑:我在输出 window 中看到下面的消息,在 google 上找不到任何关于它的信息,除了我已经检查过响应缓存中间件的几个地方。
Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware:Information: The response could not be cached for this request.
注意:我希望我可以创建#response-caching-middleware 标签。不确定#responsecache 是否相关。
如果 Cache-Control
header 正在通过,那么它正在运行。从那个角度来看,这就是服务器所能做的。客户端最终决定是否 实际上 缓存资源。发送 header 不会强制客户端做任何事情;事实上,一般情况下,服务器不能强制客户端做任何事情。
我最近也有同样的困惑。
ASP.Net Core 的 ResponseCaching 确实提供 client-side 缓存(通过 HTTP 响应 headers)和 server-side(通过 [=47 的内存缓存中间件) =] 其他中间件,如果响应在缓存中)。 server-side 部分读取 HTTP 响应缓存 headers 以确定它是否应该执行 server-side 缓存(类似于 ISP 或 CDN 可能执行的操作)。
不幸的是,调试 server-side ResponseCaching 很棘手,因为它有奇怪的规则并且没有足够的日志记录。在我的例子中,我下载了微软的源代码来逐步检查它并找到我的代码的问题。
您在输出 window "The response could not be cached for this request" 中找到的注释是一个线索。
请求的 server-side 缓存分为两部分。服务器必须在第一次请求 url 时启动缓存。它将在第二次请求时提供缓存版本。请注意错误消息何时出现,是在第一次还是第二次请求时。这会告诉您它是否无法存储在缓存中,或者是否无法从缓存中检索。
存储和检索的规则都在这个源代码文件中: https://github.com/aspnet/ResponseCaching/blob/3bf5f6a1ce69b65c998d6f5c739822a9bed4a67e/src/Microsoft.AspNetCore.ResponseCaching/Internal/ResponseCachingPolicyProvider.cs
您的 "Cache-Control:public,max-age=60" header 应该完全符合这些规则。
我的猜测是您确实可以使用它,但不知道如何正确测试它。 此问题中记录了 ResponseCaching 的 counter-intuitive 部分:https://github.com/aspnet/Home/issues/2607 本质上,如果浏览器发送 no-cache 或 no-store header(当您按下 CTRL+F5 或打开调试器工具时),ASP.Net Core 的 ResponseCaching 将响应浏览器的请求& re-generate 响应。
因此,为了测试您的代码是否正常工作,您可能加载了页面,这会启动缓存,然后按 CTRL+F5 到 force-refresh 您的浏览器并且您希望 server-side 响应使用缓存条目而不是 运行 您的 WebAPI 代码。但是,它尊重 no-cache 请求 header 并绕过缓存(并在输出日志中写入该消息)。
测试此方法的方法是清除浏览器缓存 in-between 请求(或切换到隐身模式),而不是使用 CTRL+F5。
附带说明一下,尊重 no-cache/no-store 请求 headers 可能是一个糟糕的设计选择,因为 ASP.Net Core 的 ResponseCache 很可能会被拥有响应的服务器使用,而不是像 CDN/ISP 这样的中间缓存。我已经扩展了基础 ResponseCache,并提供了一个选项来禁用对这些 header 的支持(以及将缓存序列化到磁盘,而不是仅 in-memory)。这是默认缓存的简单 drop-in 替换。
你可以在这里找到我的分机: https://github.com/speige/AspNetCore.ResponseCaching.Extensions https://www.nuget.org/packages/AspNetCore.ResponseCaching.Extensions
ResponseCaching 还存在其他一些需要注意的陷阱,您可能已经在您发布的博客 url 中读到过这些内容。 set-cookie 的经过身份验证的请求和响应不会被缓存。只有使用 GET 或 HEAD 方法的请求才会被缓存。如果 QueryString 不同,它将创建一个新的缓存条目。此外,如果请求的某些条件与 previously-cached 请求不同(例如:user-agent、accept-encoding,通常您需要 "Vary" header 来防止缓存, ETC)。最后,如果中间件处理请求,它将 short-circuit 稍后的中间件。确保您的 app.UseResponseCaching() 在 app.UseMVC()
之前注册我遇到了同样的问题,我正想着急呢,我设置了 app.UseResponseCaching();
以及 services.AddResponseCaching();
并在我的操作之上添加了 ResponseCache
与 Microsoft 官方文档中所说的完全一样,尽管 cache-controll
header 已在从服务器返回的响应中正确设置,但仍然没有缓存在 server-side.
在这个问题上费了几个小时之后,我弄清楚了问题出在哪里以及为什么没有缓存在服务器上。
浏览器默认将请求的 cache-controll
值设置为 max-age=0
(如果请求不是由返回或转发引起的)即使您在响应中正确设置了 cache-controller
在您的操作(或控制器)上添加 ResponseCache
属性,因为请求发送的 cache-controller
设置为 max-age=0
,服务器无法缓存响应,我认为这必须添加到响应缓存限制列表
无论如何,您可以通过在调用 app.UseResponseCaching();
之前添加几行代码来覆盖浏览器的默认行为,另一方面,您需要添加自定义 middle-ware 来修改请求 cache-control
header 调用前的值 app.UseResponseCaching();
.
查看下面的代码,对我有用希望对你也有用
app.Use(async (ctx, next) =>
{
ctx.Request.GetTypedHeaders().CacheControl = new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(60)
};
await next();
}
);
app.UseResponseCaching();
为了确保 ResponseCaching 按预期工作,您也可以使用邮递员,但您必须将 'Send no-cache Header'设置,见下图