强制浏览器刷新缓存、已过期的图片

5
我的网站上用户生成的图片是通过给它们一个类似于这样的src来提供的:
userImage.ashx?id={UserId}&type=avatar

在来自ashx文件的响应中,我设置了etag标题。当用户上传新图像时,etag会更改。
如果浏览器具有带有etag的缓存文件,则每当需要显示该文件时,它应该向服务器发送一个请求,并设置If-None-Match标题的标头。如果缓存的etag与服务器上的当前etag相同,则服务器以未修改-304响应。如果etag不同,则服务器以正常-200响应并开始发送新文件。
这理论上应该是如何工作的。然而,我发现对于某些浏览器(火狐和IE,默认未测试其他浏览器),情况并非如此。如果用户导航到具有缓存、已标记为etag的图像的新页面,这些浏览器将简单地使用其缓存中的图像而不发送请求。如果用户随后刷新页面,则浏览器将发送带有If-None-Match标题的请求。
所以我的问题是:用户更新其中一幅图像,然后导航到显示该图像的页面。在用户按下刷新之前,缓存的图像将被显示,即使它与新图像的etag不同。当用户按下刷新后,浏览器会发送一个带有If-None-Match标题的请求,从而触发服务器发送新图像。
是否有可能解决这个问题?
示例200响应标题:
Status=OK - 200
Date=Thu, 27 Oct 2011 14:37:31 GMT
Server=Microsoft-IIS/6.0
X-Powered-By=ASP.NET
X-AspNet-Version=4.0.30319
Transfer-Encoding=chunked
Cache-Control=public, max-age=86400
Etag="27/10/2011 13:23:30"
Content-Type=image/jpg

示例304头部:
Status=Not Modified - 304
Connection=close
Date=Thu, 27 Oct 2011 14:39:12 GMT
Server=Microsoft-IIS/6.0
X-Powered-By=ASP.NET
X-AspNet-Version=4.0.30319
Cache-Control=public, max-age=86400

(使用最后修改时间作为ETag更适合以后关于压缩等方面的需求。)

2个回答

2

据我所知,您可以通过“过期”头设置文件的有效期限。因此,如果您说“此文件在接下来的两天内有效”,浏览器就没有理由联系您的服务器。

您示例中提到的max-age基本上也是同样的效果。


我已经包含了一些头文件。我的目标是将图像缓存,直到需要更新它们。我认为这就是ETags的目的。 - Oliver
当缓存响应中存在max-age缓存控制指令时,如果其当前年龄大于在对该资源进行新请求时给定的年龄值(以秒为单位),则响应将过期。当文件是新鲜的,即不过期时,“正确的缓存必须做出响应”。 - Johan B.W. de Vries
哦,我明白了,这个想法是不设定max-age或类似的东西,但将cache-control设置为public。 - Oliver
不确定;我认为cache-control public仍然允许您的浏览器缓存文件。我想你想要的是must-revalidate。另请参阅此问题:https://dev59.com/h1fUa4cB1Zd3GeqPFzgK - Johan B.W. de Vries
cache-control public 表示位于主机和浏览器之间的代理可以缓存您的数据。cache-control private 用于您不希望位于中间的任何人持有的信息。无论如何,这与缓存失效无关。 - skillet-thief

0
我是这样解决这个问题的:
在服务器端设置一个服务,总是重定向(使用302暂时移动)到您想要显示的图像,并在用户端将图像源重置为重定向+“?”+时间戳。
这会强制浏览器再次查询图像,但让缓存起作用。
例如,您的用户端JavaScript请求/redirectme/avatar-xxx.jpg?121341并获得一个302到/avatars/avatar-xxx.jpg,然后正常请求Etag缓存。您需要支付两个往返以换取不必每次发送整个图像。
在Chrome 19中测试过(不需要时间戳查询字符串),在Firefox 10中测试过(需要时间戳)。

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