在动态DOM更改后强制重新加载具有相同网址的缓存图像

时间:2017-01-10 12:46:31

标签: http-headers single-page-application browser-cache

我正在开发一个angular2应用程序(单页面应用程序)。我的页面永远不会“重新加载”,但内容会根据用户的互动而发生变化。

我遇到了一些缓存问题,特别是图像。

上下文:

我的页面包含一个可编辑的图片列表:

<ul>
<li><img src="myImageController/1"><a href="editPage/1">Edit</a></li>
<li><img src="myImageController/2"><a href="editPage/2">Edit</a></li>
<li><img src="myImageController/3"><a href="editPage/3">Edit</a></li>
</ul>

当我想编辑图像(编辑链接)时,我的dom内容将完全更改为显示另一个带有fileupload组件的角度组件。

myImageController返回LastModified标头和cache-control:no-cache并且必须重新验证。

刷新后(点击F5),我的页面请求获取所有img src,这是正确的:如果图像已被修改,则会被下载,如果没有,我只需要304就可以了。

注意:我的图像作为blob字段存储在数据库中。

问题:

当我的页面内容使用包含img标签的单页应用程序动态重新加载时,浏览器不会调用GET http请求,而是立即从缓存中获取图像。我假设这是一个浏览器优化,以避免多次在同一页面上获取相同的资源。

错误的解决方案:

第一个解决方案是添加类似?time =(new Date())。getTime()来生成唯一的URL并避免浏览器缓存。这不会在请求中发送If-Modified-Since标头,我会每次完整地下载我的图像。

进行“真实”刷新:角度应用中的第一页加载非常慢,我不会刷新所有内容。

测试

为了简化问题,我尝试创建一个包含3个图像的静态html页面,其中包含与我的控制器完全相同的链接:/ myImageController / 1。使用chrome developper工具,我可以看到只调用一个get请求。如果我设法在这种情况下获得多个服务器调用,它可能会解决我的问题。

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

5th version of HTML specification描述了这种行为。浏览器可以重用图像而不管缓存相关的HTTP头。有关详细信息,请查看此answer。您可能需要使用XMLHttpRequest和blob。在这种情况下,您还需要考虑同源策略。

您可以使用以下功能确保用户代理执行每个请求:

var downloadImage = function ( imgNode, url ) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.responseType = "blob";
  xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {
      if (xhr.status == 200 || xhr.status == 304) {
        var blobUrl = URL.createObjectURL(xhr.response);
        imgNode.src = blobUrl;
        // You can also use imgNode.onload callback to release blob resources.
        setTimeout(function () {
          URL.revokeObjectURL(blobUrl);
        }, 1000);
      }
    }
  };
  xhr.send();
};

有关详情,请查看Eric Bidelman撰写的New Tricks in XMLHttpRequest2文章,Nicholas C. Zakas撰写的Working with files in JavaScript, Part 4: Object URLs文章以及URL.createObjectURL() MDN pageSame-origin policy MDN page

答案 1 :(得分:0)

您可以使用随机ID技巧。这将更改URL,以便浏览器重新加载图像。并非可以在查询参数中强制完全缓存中断,也可以在哈希中允许浏览器从缓存中重新验证图像(并避免在未更改的情况下避免重新下载)来完成此操作。

function reloadWithCache(img: HTMLImageElement, url: string) {
  img.src = url.replace(/#.*/, "") + "#" + Math.random();
}

function reloadBypassCache(img: HTMLImageElement, url: string) {
  let sep = img.indexOf("?") == -1? "?" : "&";
  img.src = url + sep + "nocache=" + Math.random()
}

请注意,如果您定期使用reloadBypassCache,则最好修复缓存标头。此功能将始终对您的原始服务器造成损害,从而导致更高的运行成本并使CDN失效。