为什么浏览器不尊重使用 `(new Image()).src = ...` 加载的图像 Cache-Control headers?
Why don't browsers respect Cache-Control headers for images loaded with `(new Image()).src = ...`?
测试用例:
<script>
console.log('request');
(new Image()).src = 'https://s3.amazonaws.com/mapbox-gl-js/tests/no-cache.png';
setInterval(function() {
console.log('request');
(new Image()).src = 'https://s3.amazonaws.com/mapbox-gl-js/tests/no-cache.png';
}, 5000);
</script>
Chrome 和 Firefox 都不会对第一个 no-cache.png
发出任何网络请求,尽管它是用 Cache-Control: no-cache
提供的,表明用户代理 必须 重新验证缓存的内容。
这里有几个问题 (e.g. this one) 涉及到这个问题并提供了解决方法,但我最感兴趣的是回答更基本的问题:
- 什么 Web 规范(如果有)允许或要求这种行为?
- 如果没有指定,是否至少有一个或多个浏览器正式记录?
- 网络作者对这种行为有什么控制(如果有的话)?
- 特别是,有没有一种方法可以在不失去通过
If-None-Match
重新验证的好处的情况下破坏缓存,就像使用 cache-busting 查询参数一样?
图像的特殊行为在 the HTML Standard:
中指定
Each Document
object must have a list of available images. Each image in this list is identified by a tuple consisting of an absolute URL, a CORS settings attribute mode, and, if the mode is not No CORS, an origin. Each image furthermore has an ignore higher-layer caching flag.
正是这个标志控制用户代理是否从可用图像列表中删除条目或不给定 higher-layer 资源的缓存语义(例如 HTTP Cache-Control
响应 header).
标志是设置并且当加载图像源的网络任务完成时图像添加到可用图像列表。
根据询问此行为的 Chromium 错误 this comment,Cache-Control: no-store
将覆盖 Chrome 中的此行为,但这可能会发生变化。
除了 Cache-Control: no-store
或将 cache-busting 查询参数附加到 URL 之外,这也禁用了通过 If-None-Match
重新验证的方法,我知道另一种绕过忽略的方法higher-level 缓存标志:通过 XMLHttpRequest
加载图像数据,设置 xhr.responseType = 'arraybuffer'
,用响应数据创建 Blob
object,然后将 blob 加载到一个Image
与 createObjectURL
:
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
var img = new Image();
img.onload = function() {
// ... do something with img
URL.revokeObjectURL(img.src);
};
var blob = new Blob([new Uint8Array(xhr.response)], { type: 'image/png' });
img.src = URL.createObjectURL(blob);
};
xhr.send();
测试用例:
<script>
console.log('request');
(new Image()).src = 'https://s3.amazonaws.com/mapbox-gl-js/tests/no-cache.png';
setInterval(function() {
console.log('request');
(new Image()).src = 'https://s3.amazonaws.com/mapbox-gl-js/tests/no-cache.png';
}, 5000);
</script>
Chrome 和 Firefox 都不会对第一个 no-cache.png
发出任何网络请求,尽管它是用 Cache-Control: no-cache
提供的,表明用户代理 必须 重新验证缓存的内容。
这里有几个问题 (e.g. this one) 涉及到这个问题并提供了解决方法,但我最感兴趣的是回答更基本的问题:
- 什么 Web 规范(如果有)允许或要求这种行为?
- 如果没有指定,是否至少有一个或多个浏览器正式记录?
- 网络作者对这种行为有什么控制(如果有的话)?
- 特别是,有没有一种方法可以在不失去通过
If-None-Match
重新验证的好处的情况下破坏缓存,就像使用 cache-busting 查询参数一样?
图像的特殊行为在 the HTML Standard:
中指定Each
Document
object must have a list of available images. Each image in this list is identified by a tuple consisting of an absolute URL, a CORS settings attribute mode, and, if the mode is not No CORS, an origin. Each image furthermore has an ignore higher-layer caching flag.
正是这个标志控制用户代理是否从可用图像列表中删除条目或不给定 higher-layer 资源的缓存语义(例如 HTTP Cache-Control
响应 header).
标志是设置并且当加载图像源的网络任务完成时图像添加到可用图像列表。
根据询问此行为的 Chromium 错误 this comment,Cache-Control: no-store
将覆盖 Chrome 中的此行为,但这可能会发生变化。
除了 Cache-Control: no-store
或将 cache-busting 查询参数附加到 URL 之外,这也禁用了通过 If-None-Match
重新验证的方法,我知道另一种绕过忽略的方法higher-level 缓存标志:通过 XMLHttpRequest
加载图像数据,设置 xhr.responseType = 'arraybuffer'
,用响应数据创建 Blob
object,然后将 blob 加载到一个Image
与 createObjectURL
:
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
var img = new Image();
img.onload = function() {
// ... do something with img
URL.revokeObjectURL(img.src);
};
var blob = new Blob([new Uint8Array(xhr.response)], { type: 'image/png' });
img.src = URL.createObjectURL(blob);
};
xhr.send();