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



我正在开发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内容会完全更改为显示另一个带有文件上传组件的角度组件。

myImageController返回LastModified标头和缓存控制:没有缓存,必须重新验证。

刷新后(点击F5),我的页面会请求获取所有img src,这是正确的:如果图像被修改,它就会被下载,如果没有,我只会得到一个304,这很好。

注意:我的图像以blob字段的形式存储在数据库中

问题:

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

错误的解决方案:

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

做一次"真正的"刷新:angular应用程序的第一页加载非常慢,我不想全部刷新。

测试

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

谢谢你的帮助。

HTML规范的第五个版本描述了这种行为。浏览器可以重用图像,而不考虑与缓存相关的HTTP标头。查看此答案以了解更多信息。您可能需要使用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的文章《XMLHttpRequest2中的新技巧》,《使用JavaScript中的文件》,第4部分:Nicholas C.Zakas的文章《对象URL》,以及URL.createObjectURL()MDN页面和同源策略MDN页面。

您可以使用随机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无效。

最新更新