ResponseCache属性不会在客户端缓存数据。

27
在ASP.NET Core应用程序中,我有一个返回一些数据的操作方法。我希望在客户端缓存这些数据。所以根据这里的文档,我可以在操作方法上使用ResponseCache属性。该属性会在响应中添加Cache-Control头部。

响应缓存指的是在ASP.NET Core MVC操作生成的HTTP响应上指定与缓存相关的头部。这些头部指定了您希望客户端和中间(代理)计算机如何缓存对某些请求的响应(是否缓存等)。这可以减少客户端或代理向Web服务器发出的请求数,因为将来针对同一操作的请求可能会从客户端或代理的缓存中提供服务。

此外:

响应缓存不会缓存Web服务器上的响应。它与输出缓存不同,输出缓存会在较早版本的ASP.NET和ASP.NET MVC上将响应缓存在服务器内存中。

这是我的操作方法的样子:

public class LookupController : Controller
{
    [HttpGet]
    [ResponseCache(Duration = 120)]
    public IEnumerable<StateProvinceLookupModel> GetStateProvinces()
    {
        return _domain.GetStateProvinces();
    }
}

然后我使用浏览器调用方法:http://localhost:40004/lookup/getstateprovinces。 以下是请求和响应头:

enter image description here

请注意,响应头中有Cache-Control:public,max-age-120,与预期相符。 但是,如果在120秒内使用F5刷新页面,则GetStateProvince动作方法内的调试器断点会一直命中。这意味着它没有在客户端缓存数据。

还有什么其他需要做的来启用客户端缓存吗?

更新 我已尝试使用IE,Chrome和POSTMAN,但都没有成功。每次我在地址栏中键入URL或点击刷新时,客户端(即浏览器或postman)都会调用动作方法。


1
@dotnetstep 是对的,此外 F5(刷新页面)已经是客户端的缓存代理了,就我所知。只需在地址栏中输入地址并输入即可。这就是我检查缓存的方式。 - ergen
1
@ergen 我也尝试过用POSTMAN,但没有成功。 - LP13
我不知道Postman是谁。让我们澄清一下:尝试直接在浏览器中输入URL而不是刷新页面。刷新会破坏缓存,其次文件类型对客户端缓存很重要。例如,您不希望将1000 MB的视频缓存。您只需要缓存一个.json文件,这样就无所谓了。然后,当您使用像localhost/lookup/getstateprovinces.json这样的URL时,我相信您的缓存会起作用。专注于扩展名和可缓存文件在客户端方面。即使您向响应添加标头,由于扩展名,浏览器可能不知道您的文件是静态文件。 - ergen
1
我为什么要使用filetype呢?它是一个行动方法。你从不会像这样调用行动方法:http://localhost/lookup/getstateprovinces.json 。顺便说一下,这是Postman的链接:https://www.getpostman.com/ - LP13
我并没有说你应该使用filetype。我是说当你给出一个扩展名时,你会看到缓存起作用了。我建议你确保你的_domain.GetStateProvinces();方法返回一个有效的json,并带有一个.json扩展名。这只是一个结果,甚至不是一个没有扩展名的文件。想象一下,你提供了一个.aspx页面,并命令浏览器缓存所有带有.aspx扩展名的文件。总之,尝试添加类似于扩展名或MIME类型(这取决于你的_domain.GetStateProvinces();方法返回什么以及如何返回),看看是否有效。 - ergen
3个回答

21

实际上,ResponseCache特性按照预期工作。
不同之处在于,如果您通过网站页面导航(情况1)或使用后退和前进按钮(而非刷新页面),则响应将被缓存。

情况1为例,我有以下示例:

正如您将在文章ASP.Net Core 1.1中的响应缓存中看到的那样:

在浏览器会话期间,在网站内浏览多个页面或使用后退和前进按钮访问页面时,如果内容没有过期,则将从本地浏览器缓存中提供内容。
但是,当通过F5刷新页面时,请求将转到服务器并刷新页面内容。您可以通过使用F5刷新联系页面来验证它。
因此,当您按F5时,响应缓存过期值无法发挥作用以提供内容。您应该会看到联系请求的200响应。

参考资料:
[1]. ASP.NET Core响应缓存示例
[2]. ResponseCache属性示例
[3]: 如何在所有浏览器中控制网页缓存?


Index动作方法返回View,所以你说的可能是正确的(我还没有尝试过)。然而,我的问题与返回JSON格式数据的动作方法有关。就像我在问题中发布的那个。 - LP13
如果您正在使用浏览器并且在获取缓存响应时处于指定的情况下,则Content-Type无关紧要。 关于Postman,如果您将其作为独立应用程序安装(从其网站下载),则无法为请求启用缓存功能。但是,如果您将其安装为Google Chrome的应用程序,则可以获得缓存响应。我会在答案中添加必要的信息。 - Michael
你能否请看一下我发布的问题吗? https://stackoverflow.com/questions/72755972/netcore-responsecache-does-not-work-for-some-routes - Offir

10
长话短说,使用以下方式的ResponseCache属性即可在全新的、默认的dotnet core项目中(包括async方法)实现基于过期时间的客户端缓存:
[HttpGet]
[ResponseCache(Duration = 120)]
public IEnumerable<StateProvinceLookupModel> GetStateProvinces()
{
    return _domain.GetStateProvinces();
}

在上面的截图中,Cache-Control: public,max-age=120 可见,因此它是正确工作的。在大多数情况下,在到期时间之前(即接下来的120秒或2分钟),浏览器不会发送后续请求,但这是浏览器(或其他客户端)的决定。
如果请求被发送了,你要么有一些中间件或服务器配置覆盖了响应头,要么你的客户端忽略了缓存指令。在上面的截图中,客户端忽略了缓存,因为缓存控制头在那里。
常见情况下,客户端缓存被忽略并且请求被发送:
  • Chrome使用HTTPS时,如果没有证书(或证书无效),会防止任何类型的缓存。这在本地开发中很常见,因此请在测试缓存时使用HTTP,或信任自签名证书。
  • 大多数浏览器开发工具默认禁用缓存,可以禁用此功能。
    • 通常浏览器会发送额外的头信息,Chrome会发送 Cache-Control: no-cache
  • 直接刷新(即Ctrl+F5)将指示大多数浏览器不使用缓存,并请求最新内容
    • 通常浏览器会发送额外的头信息,Chrome会发送Cache-Control: max-age=0(这在您的屏幕截图中可见)
  • Postman发送Cache-Control: no-cache头,使其绕过本地缓存,导致请求被发送;您可以从设置对话框中禁用它,这样请求将不再使用上述客户端缓存配置。
此时我们已经超出了基于过期时间的客户端缓存,服务器 将会 以某种方式接收到请求,并发生另一层缓存:您可以使服务器响应一个304 Not Modified代码(然后再次由客户端按其所需进行解释),或使用服务器端缓存并响应完整内容。或者您可以不使用任何后续缓存,只需在服务器上重新执行整个请求处理。
注意:不要将ResponseCache属性与启动配置中的services.AddResponseCaching()app.UseResponseCaching()中间件混淆,因为这是用于服务器端缓存(在使用中间件时默认使用内存缓存)。客户端缓存无需中间件即可工作,仅使用属性即可。

你能否请看一下我发布的问题吗? https://stackoverflow.com/questions/72755972/netcore-responsecache-does-not-work-for-some-routes - Offir

0

首先,我想澄清几件事情,我相信你已经知道了。

  1. ResponseCache与OutputCache并不相等。

  2. 根据我的理解,ResponseCache是设置标题,但在服务器端不会缓存任何内容。

现在,如果你想像OutputCache一样缓存,那么你可能需要使用刚发布的预览版1.1。

ASP.net core 1.1预览版本

https://blogs.msdn.microsoft.com/webdev/2016/10/25/announcing-asp-net-core-1-1-preview-1/

他们推出了新的响应缓存中间件。响应缓存中间件演示可在此处查看。https://github.com/aspnet/ResponseCaching/blob/dev/samples/ResponseCachingSample/Startup.cs

我从未表示过想要在服务器端缓存,就像OutputCache一样。事实上,我不想在服务器端缓存,我想在客户端缓存数据。这正是“ResponseCache”属性应该做的。 - LP13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接