更改整个用户图像文件结构以利用简单的浏览器缓存是否值得?


9

在我的一个移动网站上,我只是将用户的个人资料图片存储为用户文件夹中的“ 1.jpg”,然后从那里逐步上传他们上传的所有其他照片。这意味着,例如,每当他们更改个人资料照片时,文件名都保持不变。

我一直想利用图像缓存,以便每次查看和重新查看用户的个人资料时都不会一遍又一遍地下载相同的旧图片,但是与此同时,我希望我的用户的浏览器能够如果已更改,请下载新的。

从我一直在阅读的内容来看,真正做到这一点的唯一方法似乎是实际使用随机文件名并跟踪数据库中所有这些文件名,以便您可以设置一个未过期的缓存,而最近更改后的照片由于具有新文件名而再次被拉出。但是,到目前为止,我将它们进行结构化的方式的美丽之处在于,由于可以预测它们的位置,因此我可以完全跳过数据库并直接访问文件。

因此,我的问题是,为了永久缓存和在新上载时自动重新下载而改变站点的整个文件结构,并添加DB元素是否值得?

这是一项艰巨的任务,但是如果认为值得的话,那么我可以毫不犹豫地朝着这一巨大变化迈进。我只想确保这就是“大男孩”的做法,这样我就不必再更改文件结构了。

谢谢。

Answers:


7

一种常用的解决方案是使图像URL看起来像这样:

http://www.example.com/path/to/images/1.jpg?v=123456

/path/to/images/1.jpg是图片的实际URL路径,而?v=123456只是盯着URL末尾的虚拟查询。查询字符串可以是任何内容,例如版本号,时间戳,图像内容的哈希值,只要您在图像发生更改时就进行更改即可,而在不更改时保持相同。

诀窍在于,当Web服务器被要求提供这样的URL时,它将忽略查询字符串,因为URL实际上指向静态文件。但是对于用户的浏览器(以及两者之间的任何代理),具有不同查询字符串的URL将完全不同,因此对查询字符串的任何更改都将迫使浏览器重新加载文件。

因此,您可以将Web服务器配置为发送ExpiresCache-ControlHTTP标头,以允许无限期缓存,这是安全的,因为您可以通过更改查询字符串来强制重新加载。要做到这一点的方法之一,如果你使用Apache与指定mod_expires,是把一个.htaccess文件与线图像目录:

ExpiresActive On
ExpiresDefault "access plus 1 year"

许多流行的网站都使用此技术。例如,如果您查看此页面的HTML源代码,则会发现它的样式表是从这样的URL加载的:

http://cdn.sstatic.net/stackoverflow/all.css?v=7cd8ea9d6f1e

?v=7cd8ea9d6f1e就像我上面所述,这里是一个虚拟查询字符串;您可以通过更改它并确认它确实仍返回相同文件来确认这一点。


这也很有趣,但是如何确定上次修改文件的时间与第一次查看浏览器的时间,以便确定何时应该告诉用户浏览器再次获取文件(例如,通过更改查询值)?
ProgrammerGirl

1
您无需跟踪查看文件的时间。只需跟踪文件的最后更改时间(或文件的其他适当属性),然后将其包括在查询字符串中即可。这样,每当文件更改时,URL也会更改。
Ilmari Karonen

非常非常有趣。因此,我大概可以获取文件的“上次修改”属性,然后仅使查询值正确吗?
ProgrammerGirl

1
是的,应该可以。
Ilmari Karonen 2012年

1
我没有发现任何重大缺点。您可能最终会在搜索引擎索引中获得图像的重复副本,但是至少像Google这样的主要搜索引擎在处理此类问题方面非常聪明,因为这是一种常见的技巧。在任何情况下,都可以通过发送rel =“ canonical” HTTP标头并保持适当的到期时间(例如,仅一个月或一周而不是整个一年)来缓解该问题。
Ilmari Karonen 2012年

6

有多种缓存方法。

有条件的GET

如果要将这些图像存储在文件系统上并直接通过Web服务器提供它们,则可能已经在使用条件get。Web服务器将自动使用文件系统元数据来设置ETAG标头,并且如果浏览器在其请求中包含标头If-Modified-SinceIf-Matches标头,则会自动答复“ 304 Not Modified” 。(所有浏览器都可以。)

在这种情况下,不会退回整个图像,因此可以节省带宽。但是,仍然会发出GET请求,因此您仍然会有请求的开销和延迟。

您可以通过使Web服务器为图像设置Cache-Control标头来稍微减少请求数,但会牺牲高速缓存的新鲜度public,max-age=N。这表示缓存可以在最多max-age检查资源是否更新之前将其保留最多几秒钟。

但是,HTTP仅定义了一种使缓存条目无效的方法,该方法可能不符合您的应用程序的语义:如果将POST或PUT张贴到更新个人资料照片的url,则回复Location: [url of photo]标头,并且该URL的缓存条目将无效。

(通过这种机制,您可以缓存带有评论的网页,然后在用户发布新评论后由浏览器强制重新加载该页面。浏览器将回复POST /comment带有303 See Other和的Location: /page/with/comment。请注意,这并未使用由于存在长期的错误而无法在Firefox中使用。)

除非您有很多流量,否则这种缓存方法很好。

更改网址

url是资源的表示形式,因此管理缓存的另一种方法不是更改资源的缓存参数,而是使用“永远缓存”指令来创建全新的资源。这是该方法的“大男孩”的青睐,因为它可以让他们产生任何额外的要求,为他们节省大量的带宽。缺点是它需要更多的簿记。

有两种通用技术。

查询字串

当从文件系统提供文件服务时,Web服务器将忽略查询字符串。但是,缓存不会:/1.jpg?t=12345并且/1.jpg?t=67890是两个完全不同的,不相关的资源,即使服务器认为它们是相同的。

因此,您可以做的一件简单的事情就是,每当您对html中的资源进行引用时,将文件系统时间戳记附加为查询字符串,并设置一个长Expires标头。然后,浏览器将永远缓存此资源,并且只要查询字符串不变,就不会执行任何 GET。

缺点是,如果您想强制使缓存无效,则很难或不可能向网络服务器指示项目的新url。例如,如果浏览器的缓存HTML页面带有/1.jpg?v=1引用,但碰巧清除了该条目/1.jpg?v=1(可能是文件或内存空间不足),它将向发送新请求/1.jpg?v=1。如果在此期间图像已更改为/1.jpg?v=2,则正确的响应是:

  1. 服务文件的旧版本。如果您希望所有资源在某个时间点都保持一致,则可以执行此操作。例如,这是您应该对CSS文件执行的操作,因为带有旧html文件的新css文件可能无法正常工作!
  2. 使用重定向到文件的新版本301 Moved Permanently。如果您希望所有资源尽可能新,则可以这样做。

单独使用Web服务器很难做到这两者,这意味着即使是图像请求,您也需要调用Web应用程序,这可能更加复杂,而且会占用更多资源。Web 服务器提供文件的速度非常快,因此Web应用程序的开销可能最终吞噬了带宽和延迟。

档案名称

更改文件名,而不是添加查询字符串。这意味着在文件系统上保留多个版本的文件很容易,但是您可能需要存储文件元数据并进行其他数据库记账以跟踪您的资源及其名称。


0

阅读有关http状态的信息304 Not Modified,您应该能够使用304响应下载请求,并告诉服务器使用缓存的数据,然后将其重新发送到浏览器。并阅读此问题/programming/2978496/make-php-page-return-304-not-modified-if-it-hasnt-been-modified


有趣,但是这是对有问题的文件架构的“创可贴”解决方案,还是我的文件架构很好,只需要这种缓存功能?另外,如何确定文件的上次修改时间以及首次查看浏览器的时间,以确定我何时应该告诉用户的浏览器再次获取文件?
ProgrammerGirl

我不太熟悉它,所以认为弗朗西斯·阿维拉(Francis Avila)对它了解得更多
Puggan Se 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.