ASP.NET Core 2.0-Http响应缓存中间件-未缓存任何内容

问题描述:

我从Visual Studio中的WebApi .Net Core 2.0模板创建了一个新的解决方案. 我在启动时添加了以下内容.

I created a new solution from WebApi .Net Core 2.0 template in Visual Studio. I added the following in startup.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddHttpCacheHeaders(opt => opt.MaxAge = 600);
    services.AddResponseCaching();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseResponseCaching();
    app.UseHttpCacheHeaders();
    app.UseMvc();
}

然后和邮递员一起点击http://localhost:xxxx/api/values,这是模板创建的端点,并返回["value1","value2"]

Then, with postman, I hit http://localhost:xxxx/api/values which is a endpoint created by the template and that returns ["value1","value2"]

请注意,我确保Postman不会发送无缓存标头(在Postman设置中).

Note that I made sure that Postman doesn't send no-cache header (in Postman settings).

HttCacheHeaders服务来自于存储库.它添加了HTTP缓存头.所以我的端点响应头是:

The HttCacheHeaders service comes from that repo. It adds HTTP Cache Headers. So my endpoint response header is:

  • 缓存控制:public,max-age = 600
  • 内容类型:application/json; charset = utf-8
  • 日期:2017年9月29日星期五14:02:29 GMT
  • ETag:C5DFA8974BB722D27E71EE50D3D14625
  • 过期:2017年9月29日星期五14:03:29 GMT
  • 上次修改时间:2017年9月29日星期五,格林尼治标准时间
  • 服务器:Kestrel
  • 传输编码:分块
  • 不同:接受,接受语言,接受编码
  • X-Powered-By:ASP.NET
  • X-SourceFiles:=?UTF-8?B?................
  • Cache-Control: public,max-age=600
  • Content-Type: application/json; charset=utf-8
  • Date: Fri, 29 Sep 2017 14:02:29 GMT
  • ETag: C5DFA8974BB722D27E71EE50D3D14625
  • Expires: Fri, 29 Sep 2017 14:03:29 GMT
  • Last-Modified: Fri, 29 Sep 2017 14:02:29 GMT
  • Server: Kestrel
  • Transfer-Encoding: chunked
  • Vary: Accept, Accept-Language, Accept-Encoding
  • X-Powered-By: ASP.NET
  • X-SourceFiles: =?UTF-8?B?................

问题是什么都没有被缓存. Ouput窗口仅显示The response could not be cached for this request.

The problem is that nothing gets cached. the Ouput windows only shows The response could not be cached for this request.

所以我对如何使用ASP.NET Core ResponseCaching Middleware有点迷茫.

So I'm a bit lost on how to use ASP.NET Core ResponseCaching Middleware.

更新

如果我不使用HttCacheHeaders服务,但将[ResponseCache(Duration = 600)]添加到控制器的操作中,则缓存有效.
请注意,我要使用HttCacheHeaders的原因是为了使ETagLast-Modified稍后进行验证缓存以及过期缓存.

Update

If I don't use the HttCacheHeaders service but add [ResponseCache(Duration = 600)] to the action of my controller, the cache works.
Note that reason that I want to use HttCacheHeaders is for ETag and Last-Modified to later do Validation Caching as well as Expiration Caching.

这是一种无解答,带有一些故障排除提示.

This is kind of a non-answer, with some troubleshooting tips.

我尝试了您的确切代码&它对我来说很好.也许已在HttpCacheHeaders或ResponseCaching存储库中修复了一个错误?

I tried your exact code & it worked fine for me. Maybe a bug has been fixed in the HttpCacheHeaders or ResponseCaching repo?

不幸的是,调试服务器端ResponseCaching很棘手,因为它具有怪异的规则&没有足够的日志记录.过去,当我遇到类似的问题时,我不得不撤消Microsoft的源代码以逐步完成&找到我的代码存在的问题.

Unfortunately, debugging the server-side ResponseCaching is tricky because it has weird rules & there's not adequate logging. When I've had similar issues with it in the past I've had to pull down Microsoft's source code to step through it & find the issue with my code.

您在输出窗口中找到的注释无法为此请求缓存响应"是一个提示.

The note you found in the output window "The response could not be cached for this request" is a clue.

请求的服务器端缓存分为两部分.服务器必须在第一次请求url时准备好缓存.它将第二次请求缓存的版本.请注意错误消息出现的时间(如果是第一个或第二个请求).它将告诉您它是否无法存储在缓存中,或者是否无法从缓存中检索.

There's 2 parts to the server-side caching of a request. The server has to prime the cache the first time the url is requested. 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

您的"Cache-Control:public,max-age = 600"标头应与这些规则完全匹配.

Your "Cache-Control:public,max-age=600" header should match these rules just fine.

您已经找到了没有缓存/没有存储的陷阱".还有其他一些带有ResponseCaching的控件,请注意:

You already found the no-cache/no-store "gotcha". There are also a few other others with ResponseCaching to watch out for:

已认证的请求和带有set-cookie的响应将不会被缓存.仅使用GET或HEAD方法的请求将被缓存.如果QueryString不同,它将创建一个新的缓存条目.另外,通常,如果请求的某些条件不同于先前缓存的请求(例如,用户代理,accept-encoding等),通常您会希望使用"Vary"标头来防止缓存.

Authenticated requests & responses with set-cookie won't be cached. Only requests using GET or HEAD method will be cached. If the QueryString is different, it'll make a new cache entry. 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).

另一方面,由于ASP.Net Core的ResponseCache很可能会由拥有响应的服务器而不是像中间缓存这样的服务器使用,因此遵守no-cache/no-store请求标头可能是一个糟糕的设计选择. CDN/ISP.我已经对基本ResponseCache进行了扩展,提供了一个禁用这些标头的选项(以及将缓存序列化到磁盘上,而不是仅在内存中).这是默认缓存的便捷替代.

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. 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). It's an easy drop-in replacement for the default cache.

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

You can find my extension here: https://github.com/speige/AspNetCore.ResponseCaching.Extensions https://www.nuget.org/packages/AspNetCore.ResponseCaching.Extensions