12

我想在 asp.net core 2.0 中使用服务器端响应缓存(输出缓存),发现了响应缓存中间件,并想尝试一个全新的 asp.core mvc 项目。

这是上面链接中的描述,这让我认为这可以像输出缓存一样使用。

中间件确定响应何时可缓存、存储响应并提供来自缓存的响应。

这是我的 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>&copy; 2018 - ResponseCachingMiddleware - @DateTime.UtcNow</p>

Cache-Control 标头似乎很好,这是我在加载页面时在标头中得到的,但时间戳会在每秒每次刷新时不断更新。

Cache-Control:public,max-age=60

我从 MS 文档中了解到的是响应缓存中间件是服务器端缓存机制,负责缓存响应,而响应缓存似乎只是一个过滤器来操作缓存的响应标头。

无法判断我的理解或代码是否有问题,我想抱怨自从我开始使用 ASP.Net Core 进行原型设计以来,我经常有这种感觉。也许您还可以建议更好的资源作为附带主题。

我在 ASP.NET Core 2.0 之前查看过这篇文章 - Http Response Caching Middleware - Nothing cached

也检查了这一点,但似乎唯一的区别是我使用的是 mvc。 https://github.com/aspnet/ResponseCaching/blob/dev/samples/ResponseCachingSample/Startup.cs

谢谢

编辑:我在输出窗口中看到下面的消息,除了我已经检查过响应缓存中间件的几个地方之外,在谷歌上找不到任何关于它的信息。

Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware:信息:无法缓存此请求的响应。

注意:我希望我可以创建#response-caching-middleware 标签。不确定#responsecache 是否相关。

4

3 回答 3

17

我遇到了同样的问题,我正要大发雷霆,我已经设置app.UseResponseCaching();好了services.AddResponseCaching();并添加ResponseCache了我的操作,就像微软官方文档中所说的一样,尽管cache-controll标题在响应返回时设置正确来自服务器,但在服务器端仍然没有缓存。

在这个问题上花费了几个小时后,我弄清楚了问题出在哪里以及为什么没有缓存在服务器上。

浏览器默认为请求设置cache-controllmax-age=0(如果请求不是由后退或转发引起的),即使您通过在操作(或控制器)顶部cache-controller添加属性在响应中正确设置,因为请求发送的设置为,服务器无法缓存响应,我认为这也必须添加到响应缓存限制列表中ResponseCachecache-controllermax-age=0

无论如何,您可以通过在调用之前添加几行代码来覆盖浏览器默认行为,app.UseResponseCaching();另一方面,您需要在调用之前添加自定义中间件来修改请求cache-control标头值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 按预期工作,您也可以使用邮递员,但您必须在设置中将“发送无缓存标头”设置为关闭,请参见下图

在此处输入图像描述

于 2018-08-10T11:16:07.633 回答
14

我最近也有同样的困惑。

ASP.Net Core 的 ResponseCaching 确实提供了客户端缓存(通过 HTTP 响应标头)和服务器端(通过内存缓存的中间件,如果响应在缓存中,该中间件会短路其他中间件)。服务器端部分读取 HTTP 响应缓存标头以确定它是否应该进行服务器端缓存(类似于 ISP 或 CDN 可能会做的事情)。

不幸的是,调试服务器端 ResponseCaching 很棘手,因为它有奇怪的规则并且没有足够的日志记录。就我而言,我下载了 Microsoft 的源代码以单步执行它并找到我的代码的问题。

您在输出窗口“无法缓存此请求的响应”中找到的注释是一条线索。

请求的服务器端缓存有 2 个部分。服务器必须在第一次请求 url 时填充缓存。它将在第二次请求时提供缓存版本。请注意错误消息何时出现,如果它是在第一个或第二个请求上。这将告诉您它是否无法存储在缓存中,或者是否无法从缓存中检索。

存储和检索的规则都在这个源代码文件中: https ://github.com/aspnet/ResponseCaching/blob/3bf5f6a1ce69b65c998d6f5c739822a9bed4a67e/src/Microsoft.AspNetCore.ResponseCaching/Internal/ResponseCachingPolicyProvider.cs

您的“Cache-Control:public,max-age=60”标头应该符合这些规则就好了。

我的猜测是你实际上让它工作,但不知道如何正确测试它。本期中提到的 ResponseCaching 有一个违反直觉的部分:https ://github.com/aspnet/Home/issues/2607 本质上,如果浏览器发送 no-cache 或 no-store 标头(当您点击 CTRL+ F5 或打开调试器工具),ASP.Net Core 的 ResponseCaching 将接受浏览器的请求并重新生成响应。

因此,为了测试您的代码是否正常工作,您可能加载了已启动缓存的页面,然后您按 CTRL+F5 强制刷新您的浏览器,并且您希望服务器端响应缓存条目而不是运行您的 WebAPI代码。但是,它尊重无缓存请求标头并绕过缓存(并在输出日志中写入该消息)。

对此进行测试的方法是清除请求之间的浏览器缓存(或切换到隐身模式),而不是使用 CTRL+F5。

附带说明一下,尊重 no-cache/no-store 请求标头可能是一个糟糕的设计选择,因为 ASP.Net Core 的 ResponseCache 很可能由拥有响应的服务器使用,而不是像 CDN/这样的中间缓存互联网服务提供商。我已经扩展了基本的 ResponseCache 选项,以禁用尊重这些标头(以及将缓存序列化到磁盘,而不是仅在内存中)。它是默认缓存的简单替代品。

你可以在这里找到我的扩展: https ://github.com/speige/AspNetCore.ResponseCaching.Extensions https://www.nuget.org/packages/AspNetCore.ResponseCaching.Extensions

还有一些其他的 ResponseCaching 问题需要注意,您可能已经在您发布的博客 URL 中阅读过这些问题。使用 set-cookie 验证的请求和响应不会被缓存。只有使用 GET 或 HEAD 方法的请求才会被缓存。如果 QueryString 不同,它将创建一个新的缓存条目。此外,如果请求的某些条件与先前缓存的请求不同(例如:用户代理、接受编码等),通常您需要一个“Vary”标头来防止缓存。最后,如果一个中间件处理一个请求,它会短路后面的中间件。确保您的 app.UseResponseCaching() 在 app.UseMVC() 之前注册

于 2018-02-16T07:41:10.763 回答
-1

如果Cache-Control标题通过,那么它正在工作。从这个角度来看,这就是服务器所能做的一切。客户端最终决定是否实际缓存资源。发送标头不会强制客户端做任何事情;事实上,服务器通常不能强迫客户端做任何事情。

于 2018-01-12T19:36:43.447 回答