如何强制Web浏览器不缓存图像

时间:2020-03-06 14:39:27  来源:igfitidea点击:

背景

我正在为两个公益网站编写和使用一个非常简单的基于CGI的(Perl)内容管理工具。它为网站管理员提供事件的HTML表单,这些表单将填写字段(日期,位置,标题,描述,链接等)并保存。在该表格上,我允许管理员上传与事件相关的图像。在显示表单的HTML页面上,我还显示了上载图片的预览(HTML img标签)。

问题

当管理员想要更改图片时,会发生此问题。他只需要点击"浏览"按钮,选择一张新照片,然后按OK。而且这很好。

上载图像后,我的后端CGI将处理上载并正确地重新加载表单。

问题是显示的图像没有刷新。即使数据库保存了正确的图像,仍会显示旧图像。我将其范围缩小为在网络浏览器中缓存了图像。如果管理员点击Firefox / Explorer / Safari中的RELOAD按钮,则一切都会刷新,并且会出现新图像。

我的解决方案-无法正常工作

我试图通过写一个HTTP Expires指令来控制缓存,该指令的日期已经过去了。

Expires: Mon, 15 Sep 2003 1:00:00 GMT

请记住,我在管理方面,我并不在乎页面是否需要花费更长的时间加载,因为它们总是过期。

但是,这也不起作用。

笔记

上载图像时,其文件名不保留在数据库中。它被重命名为Image.jpg(以简化使用时的处理)。用新图像替换现有图像时,名称也不会更改。只是图像文件的内容会更改。

Web服务器由托管服务/ ISP提供。它使用Apache。

问题

有没有一种方法可以强制Web浏览器不缓存该页面中的内容,甚至不缓存图像?

我正在尝试使用数据库来实际"保存文件名"的选项。这样,如果更改了图像,IMG标签的src也将更改。但是,这需要对整个站点进行大量更改,如果我有更好的解决方案,我宁愿不做。此外,如果上传的新图像具有相同的名称,这仍然将不起作用(例如,将该图像进行了照片购物并重新上传)。

解决方案

简单修复:将随机查询字符串添加到图像:

<img src="foo.cgi?random=323527528432525.24234" alt="">

HTTP RFC的内容:

Cache-Control: no-cache

但这不能很好地工作:)

由于我们和客户端之间可能存在行为不当的透明代理,因此完全保证图像不会被缓存的唯一方法是为其提供唯一的uri,例如将时间戳记为查询字符串或者其中的一部分。小路。

如果该时间戳对应于映像的最后更新时间,则可以在需要时进行缓存,并在适当的时间提供新映像。

阿明·罗纳彻(Armin Ronacher)的想法正确。问题在于随机字符串可能会发生冲突。我会用:

<img src="picture.jpg?1222259157.415" alt="">

其中" 1222259157.415"是服务器上的当前时间。 (注意:我使用python的time.time()生成了该代码)

我们可能会编写用于提供图像的代理脚本,但这需要更多的工作。像这样的东西:

HTML:

<img src="image.php?img=imageFile.jpg&some-random-number-262376" />

脚本:

// PHP
if( isset( $_GET['img'] ) && is_file( IMG_PATH . $_GET['img'] ) ) {

  // read contents
  $f = open( IMG_PATH . $_GET['img'] );
  $img = $f.read();
  $f.close();

  // no-cache headers - complete set
  // these copied from [php.net/header][1], tested myself - works
  header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Some time in the past
  header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); 
  header("Cache-Control: no-store, no-cache, must-revalidate"); 
  header("Cache-Control: post-check=0, pre-check=0", false); 
  header("Pragma: no-cache"); 

  // image related headers
  header('Accept-Ranges: bytes');
  header('Content-Length: '.strlen( $img )); // How many bytes we're going to send
  header('Content-Type: image/jpeg'); // or image/png etc

  // actual image
  echo $img;
  exit();
}

实际上,在图像src处使用无缓存头或者随机数就足够了,但是由于我们希望做到防弹。

When uploading an image, its filename is not kept in the database. It is renamed as Image.jpg (to simply things out when using it).

对此进行更改,就可以解决问题。我使用时间戳,以及上面建议的解决方案:Image- <timestamp> .jpg

大概可以解决通过为图像保留相同的文件名而避免的任何问题,但是我们无需说明它们是什么。

我假设原始问题是关于存储有一些文本信息的图像。因此,如果在生成src = ... url时可以访问文本上下文,请考虑存储/使用图像字节的CRC32,而不是无意义的随机或者时间戳。然后,如果正在显示包含大量图像的页面,则仅重新加载更新的图像。最终,如果无法存储CRC,则可以在运行时计算并添加到url中。