简体   繁体   English

ASP.Net Core 2.0 - ResponseCaching Middleware - 不在服务器上缓存

[英]ASP.Net Core 2.0 - ResponseCaching Middleware - Not Caching on Server

I want to use server-side response caching (output cache) with asp.net core 2.0 and found out about Response Caching Middleware and wanted to give it a try with a brand new asp.core mvc project.我想在 asp.net core 2.0 中使用服务器端响应缓存(输出缓存),并发现了响应缓存中间件,并想尝试使用全新的 asp.core mvc 项目。

Here is the description from the link above which makes me think this could be used like output cache.这是上面链接中的描述,这让我认为这可以像输出缓存一样使用。

The middleware determines when responses are cacheable, stores responses, and serves responses from cache.中间件确定响应何时可缓存、存储响应并提供来自缓存的响应。

Here is how my startup.cs looks like.这是我的 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?}");
        });
    }
}

and here is the HomeController.cs这是 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 });
    }
}

there is also a timestamp at the bottom of _Layout.cshtml file so i can tell when the page is rendered, like below. _Layout.cshtml 文件底部还有一个时间戳,因此我可以判断页面何时呈现,如下所示。

<p>&copy; 2018 - ResponseCachingMiddleware - @DateTime.UtcNow</p>

Cache-Control headers seem to be fine, this is what I get in headers when I load the page but time stamp keeps getting updated on every refresh every second. Cache-Control 标头似乎没问题,这就是我在加载页面时在标头中得到的内容,但时间戳会在每秒刷新时不断更新。

Cache-Control:public,max-age=60

What I'm understanding from MS documentations is Response Caching Middleware is the server-side caching mechanism that takes care of caching the response while Response Caching seems to be just a filter to manipulate response headers for caching.我从 MS 文档中了解到的是响应缓存中间件是服务器端缓存机制,它负责缓存响应,而响应缓存似乎只是一个过滤器来操纵响应头进行缓存。

Can't tell if there is something wrong with my understanding or code and I wanna complain that I'm feeling this way too often since I started prototyping with ASP.Net Core.不知道我的理解或代码是否有问题,我想抱怨说自从我开始使用 ASP.Net Core 进行原型设计以来,我经常有这种感觉。 Maybe you could also suggest better resources as a side topic.也许您还可以建议更好的资源作为副主题。

I've checked out this post before ASP.NET Core 2.0 - Http Response Caching Middleware - Nothing cached我在ASP.NET Core 2.0 - Http Response Caching Middleware - Nothing cached之前查看过这篇文章

Also checked this out but it seems like the only difference is I'm using mvc.也检查了这一点,但似乎唯一的区别是我使用的是 mvc。 https://github.com/aspnet/ResponseCaching/blob/dev/samples/ResponseCachingSample/Startup.cs https://github.com/aspnet/ResponseCaching/blob/dev/samples/ResponseCachingSample/Startup.cs

Thanks谢谢

Edit: I'm seeing the message below in the output window, cannot find anything about it on google except the few places I already checked for response caching middleware.编辑:我在输出窗口中看到下面的消息,除了我已经检查过响应缓存中间件的几个地方之外,在谷歌上找不到任何关于它的信息。

Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware:Information: The response could not be cached for this request. Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware:Information: 无法为此请求缓存响应。

Note: I wish I could create #response-caching-middleware tag.注意:我希望我可以创建 #response-caching-middleware 标签。 Not sure #responsecache is relevant.不确定 #responsecache 是否相关。

I had the same issue, I was about to pull my hairs over it, I'd set app.UseResponseCaching();我遇到了同样的问题,我正准备把头发拉过去,我设置了app.UseResponseCaching(); as well as services.AddResponseCaching();以及services.AddResponseCaching(); and add ResponseCache on top of my action exactly like what was told in Microsoft official Docs, despite the the cache-controll header was set correctly on response returning from server but still nothing cached at server-side.并在我的操作之上添加ResponseCache就像微软官方文档中所说的那样,尽管在从服务器返回的响应中正确设置了cache-controll标头,但在服务器端仍然没有缓存。

After couple of hours of sweating on this issue I figured out where the problem arises and why nothing cached at server.在这个问题上花了几个小时的汗水后,我想出了问题出在哪里以及为什么没有缓存在服务器上。

Browsers by default set cache-controll value to max-age=0 for the request (if the request is not caused by back or forward) even though you set cache-controller correctly in your response by adding ResponseCache attribute on top of you action (or controller) since the cache-controller sent by request is set to max-age=0 , the server is unable to cache response, I think this must be added to list of Response Caching limitation as well默认情况下,浏览器将请求的cache-controll值设置为max-age=0 (如果请求不是由后退或前进引起的),即使您通过在操作顶部添加ResponseCache属性在响应中正确设置了cache-controller (或控制器)由于请求发送的cache-controller设置为max-age=0 ,服务器无法缓存响应,我认为这也必须添加到响应缓存限制列表中

Anyway you can override browser default behavior by adding few line of code right before calling app.UseResponseCaching();无论如何,您可以通过在调用app.UseResponseCaching();之前添加几行代码来覆盖浏览器默认行为app.UseResponseCaching(); on the other hand you need to add a custom middle-ware to modify request cache-control header value before calling app.UseResponseCaching();另一方面,在调用app.UseResponseCaching();之前,您需要添加一个自定义中间件来修改请求cache-control标头值app.UseResponseCaching(); . .

See code below, worked for me hope work for you too请参阅下面的代码,对我有用,希望对你也有用

 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();

for ensuring that ResponseCaching works as expected you can also use postman but you must set 'Send no-cache Header' to off in the setting, see image below为确保 ResponseCaching 按预期工作,您也可以使用邮递员,但您必须在设置中将“发送无缓存标头”设置为关闭,请参见下图

在此处输入图片说明

I had this same confusion recently.我最近也有同样的困惑。

ASP.Net Core's ResponseCaching does provide both client-side caching (through HTTP response headers) & server-side (through a memory cache'd middleware that short-circuits other middlewares if the response is in the cache). ASP.Net Core 的 ResponseCaching 确实提供了客户端缓存(通过 HTTP 响应标头)和服务器端(通过内存缓存的中间件,如果响应在缓存中,它会使其他中间件短路)。 The server-side portion reads the HTTP response cache headers to determine if it should do server-side caching (similar to what an ISP or CDN might do).服务器端部分读取 HTTP 响应缓存标头以确定它是否应该进行服务器端缓存(类似于 ISP 或 CDN 可能会做的事情)。

Unfortunately, debugging the server-side ResponseCaching is tricky because it has weird rules & there's not adequate logging.不幸的是,调试服务器端 ResponseCaching 很棘手,因为它有奇怪的规则并且没有足够的日志记录。 In my case I pulled down Microsoft's source code to step through it & find the issue with my code.就我而言,我拉下 Microsoft 的源代码以逐步完成并找到我的代码的问题。

The note you found in the output window "The response could not be cached for this request" is a clue.您在输出窗口中找到的注释“无法为此请求缓存响应”是一个线索。

There's 2 parts to the server-side caching of a request.请求的服务器端缓存有 2 个部分。 The server has to prime the cache the first time the url is requested.服务器必须在第一次请求 url 时准备缓存。 It will serve the cached version the 2nd time it's requested.它将在第二次请求时提供缓存版本。 Pay attention to when the error message shows up, if it's on the 1st or 2nd request.注意错误消息出现的时间,是在第一个或第二个请求上。 That'll tell you if it couldn't be stored in the cache or if it couldn't be retrieved from the cache.这将告诉您它是否无法存储在缓存中,或者是否无法从缓存中检索。

The rules for both storage & retrieval are in this source code file: https://github.com/aspnet/ResponseCaching/blob/3bf5f6a1ce69b65c998d6f5c739822a9bed4a67e/src/Microsoft.AspNetCore.ResponseCaching/Internal/ResponseCachingPolicyProvider.cs存储和检索的规则在这个源代码文件中: https : //github.com/aspnet/ResponseCaching/blob/3bf5f6a1ce69b65c998d6f5c739822a9bed4a67e/src/Microsoft.AspNetCore.ResponseCaching/Internal/ResponseCachingPolicyProvider.cs

Your "Cache-Control:public,max-age=60" header should match these rules just fine.您的 "Cache-Control:public,max-age=60" 标头应该很好地匹配这些规则。

My guess is you actually had it working, but didn't know how to test it correctly.我的猜测是你实际上让它工作了,但不知道如何正确测试它。 There is a counter-intuitive portion of ResponseCaching noted in this issue: https://github.com/aspnet/Home/issues/2607 Essentially, if the browser sends a no-cache or no-store header (when you hit CTRL+F5 or have your debugger tools open), ASP.Net Core's ResponseCaching will honor the browser's request & re-generate the response.本期中提到的 ResponseCaching 有一个违反直觉的部分: https : //github.com/aspnet/Home/issues/2607本质上,如果浏览器发送 no-cache 或 no-store 标头(当您点击 CTRL+ F5 或打开调试器工具),ASP.Net Core 的 ResponseCaching 将响应浏览器的请求并重新生成响应。

So, to test if your code was working you probably loaded the page, which primed the cache, then you hit CTRL+F5 to force-refresh your browser & you expected the server-side to respond with a cached entry rather than running your WebAPI code.因此,为了测试您的代码是否正常工作,您可能加载了启动缓存的页面,然后按 CTRL+F5 强制刷新浏览器,并且您希望服务器端响应缓存条目而不是运行您的 WebAPI代码。 However, it honored the no-cache request header & bypassed the cache (& wrote that message in your output log).但是,它尊重无缓存请求标头并绕过缓存(并在输出日志中写入该消息)。

The way to test this would be to clear your browser cache in-between requests (or switch to incognito), rather than using CTRL+F5.对此进行测试的方法是在请求之间清除浏览器缓存(或切换到隐身模式),而不是使用 CTRL+F5。

On a side note, honoring the no-cache/no-store request headers was probably a poor design choice since ASP.Net Core's ResponseCache will most likely be used by a server who owns the response, rather than an intermediary cache like a CDN/ISP.附带说明一下,遵守 no-cache/no-store 请求标头可能是一个糟糕的设计选择,因为 ASP.Net Core 的 ResponseCache 很可能由拥有响应的服务器使用,而不是像 CDN/ 这样的中间缓存互联网服务提供商。 I've extended the base ResponseCache with an option to disable honoring these headers (as well as serialize the cache to disk, rather than in-memory only).我已经扩展了基本 ResponseCache 一个选项来禁用这些标头(以及将缓存序列化到磁盘,而不是仅在内存中)。 It's an easy drop-in replacement for the default cache.这是默认缓存的简单替代品。

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

There are also a few other other gotchas with ResponseCaching to watch out for which you may have already read about in the blog urls you posted.还有其他一些关于 ResponseCaching 的问题需要注意,您可能已经在您发布的博客 URL 中阅读了这些问题。 Authenticated requests & responses with set-cookie won't be cached.带有 set-cookie 的经过身份验证的请求和响应不会被缓存。 Only requests using GET or HEAD method will be cached.只有使用 GET 或 HEAD 方法的请求才会被缓存。 If the QueryString is different, it'll make a new cache entry.如果 QueryString 不同,它将创建一个新的缓存条目。 Also, usually you'll want a "Vary" header to prevent caching if certain conditions of a request differ from the previously-cached request (example: user-agent, accept-encoding, etc).此外,如果请求的某些条件与先前缓存的请求(例如:用户代理、接受编码等)不同,通常您需要一个“Vary”标头来防止缓存。 Finally, if a Middleware handles a request it'll short-circuit later Middlewares.最后,如果中间件处理请求,它将短路后面的中间件。 Make sure your app.UseResponseCaching() is registered before app.UseMVC()确保您的 app.UseResponseCaching() 在 app.UseMVC() 之前注册

If the Cache-Control header is coming through, then it's working.如果Cache-Control标头通过,则它正在工作。 That's all the server can do from that perspective.从这个角度来看,这就是服务器所能做的。 The client ultimately makes the decision whether or not to actually cache the resource.客户端最终决定是否实际缓存资源。 Sending the header doesn't force the client to do anything;发送标头不会强制客户端做任何事情; in fact, the server, in general, cannot force the client to do anything.事实上,服务器通常不能强迫客户端做任何事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM