我如何使用 Service Worker 处理 AWS s3 导致的 non-CORS 污染的浏览器缓存?
How do I handle non-CORS polluted browser cache resulting from AWS s3, with my Service Worker?
我公司有许多应用程序请求位于 AWS S3 上的共享资源。其中一些应用程序使用 crossorigin="anonymous" html element, and some do not. AWS does not send back CORS response headers, like 'Allow-access-control-origin,' when there is no Origin request header。因此,某些用户可能会得到一个没有 CORS 响应的文件的浏览器缓存版本 headers。
当这些用户访问我团队的应用程序时,Service Worker 可能无法请求这些共享资产,因为浏览器磁盘缓存以 non-cors 方式拥有它们。错误如下所示:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8001' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
当然我不能使用不透明的响应来进行可靠的缓存。
我想我可以应用 cache-control 请求 header 来绕过浏览器缓存,但是 Fetch API Request is immutable. So, I cannot add headers to the existing request. If I try to make a new Request, I cannot get a CORS response back from AWS, because Origin is a forbidden header 的 Headers object 我不能在 Fetch API 中设置。
如果满足以下条件,此问题将得到解决:
我可以强制我公司的所有团队确保他们使用 crossorigin html 属性,但我不能。
我可以让 AWS 始终响应 CORS headers,但我做不到。
使用 Origin header 发出获取请求,但我不能。
说服我的组织设置 cache-control header 不允许浏览器缓存资产,但这是个坏主意。
我能做些什么来克服这个问题吗?现在,我只是在这些共享资产上禁用 Service Worker 缓存,以避免网络故障。
我想我会让我的应用程序使用特定于我的应用程序的查询字符串来请求所有这些共享资产。感觉不对,但应该可以。
编辑 - 感谢 Jeff,我不必清除浏览器缓存。当服务人员需要资产时,我总是可以通过网络访问。这就是我正在做的,它可以发出一个避免浏览器磁盘缓存的 CORS 请求:
function respondWithCacheOrNetwork(event) {
var headers = new Headers();
event.request.headers.forEach((v, k) => { headers.set(k, v); });
// Copy the old headers, cannot modify because immutable
headers.set('cache-control', 'no-cache');
var skipBrowserCacheRequest = new Request(event.request.url,
{
mode: 'cors',
method: event.request.method,
headers: headers
}
);
event.respondWith(toolbox.cacheFirst(skipBrowserCacheRequest));
}
看起来我们想要更多地控制我们的服务工作者如何处理缓存,例如 Firefox 中的新缓存选项,详见此处:https://hacks.mozilla.org/2016/03/referrer-and-cache-control-apis-for-fetch/
这是要在此处实施的现有 Chromium 问题 https://bugs.chromium.org/p/chromium/issues/detail?id=453190
理想情况下我们会这样做:
// Download a resource with cache busting, to bypass the cache
// completely.
fetch("some.json", {cache: "no-store"}) // or "reload"
.then(function(response) { /* consume the response */ });
你说如果你能用一个来源header发出一个获取请求,你的问题就会得到解决,但我不能。
您应该能够通过构建自己的 Request
并将 mode
显式设置为 'cors'
来做到这一点。这是一个例子:
const failingRequest = new Request('https://example.com', {
mode: 'cors'
});
fetch(failingRequest).then(console.log).catch(console.warn);
const successfulRequest = new Request('https://cors-test.appspot.com/test', {
mode: 'cors'
});
fetch(successfulRequest).then(console.log).catch(console.warn);
您应该会看到向 https://example.com
和 https://cors-test.appspot.com/test
发出了 CORS-enabled 请求。第一个请求将失败,因为服务器不支持 CORS,而第二个请求将成功并以 non-opaque Response
object.
解析
我公司有许多应用程序请求位于 AWS S3 上的共享资源。其中一些应用程序使用 crossorigin="anonymous" html element, and some do not. AWS does not send back CORS response headers, like 'Allow-access-control-origin,' when there is no Origin request header。因此,某些用户可能会得到一个没有 CORS 响应的文件的浏览器缓存版本 headers。
当这些用户访问我团队的应用程序时,Service Worker 可能无法请求这些共享资产,因为浏览器磁盘缓存以 non-cors 方式拥有它们。错误如下所示:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8001' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
当然我不能使用不透明的响应来进行可靠的缓存。
我想我可以应用 cache-control 请求 header 来绕过浏览器缓存,但是 Fetch API Request is immutable. So, I cannot add headers to the existing request. If I try to make a new Request, I cannot get a CORS response back from AWS, because Origin is a forbidden header 的 Headers object 我不能在 Fetch API 中设置。
如果满足以下条件,此问题将得到解决:
我可以强制我公司的所有团队确保他们使用 crossorigin html 属性,但我不能。
我可以让 AWS 始终响应 CORS headers,但我做不到。
使用 Origin header 发出获取请求,但我不能。
说服我的组织设置 cache-control header 不允许浏览器缓存资产,但这是个坏主意。
我能做些什么来克服这个问题吗?现在,我只是在这些共享资产上禁用 Service Worker 缓存,以避免网络故障。
我想我会让我的应用程序使用特定于我的应用程序的查询字符串来请求所有这些共享资产。感觉不对,但应该可以。
编辑 - 感谢 Jeff,我不必清除浏览器缓存。当服务人员需要资产时,我总是可以通过网络访问。这就是我正在做的,它可以发出一个避免浏览器磁盘缓存的 CORS 请求:
function respondWithCacheOrNetwork(event) {
var headers = new Headers();
event.request.headers.forEach((v, k) => { headers.set(k, v); });
// Copy the old headers, cannot modify because immutable
headers.set('cache-control', 'no-cache');
var skipBrowserCacheRequest = new Request(event.request.url,
{
mode: 'cors',
method: event.request.method,
headers: headers
}
);
event.respondWith(toolbox.cacheFirst(skipBrowserCacheRequest));
}
看起来我们想要更多地控制我们的服务工作者如何处理缓存,例如 Firefox 中的新缓存选项,详见此处:https://hacks.mozilla.org/2016/03/referrer-and-cache-control-apis-for-fetch/ 这是要在此处实施的现有 Chromium 问题 https://bugs.chromium.org/p/chromium/issues/detail?id=453190
理想情况下我们会这样做:
// Download a resource with cache busting, to bypass the cache
// completely.
fetch("some.json", {cache: "no-store"}) // or "reload"
.then(function(response) { /* consume the response */ });
你说如果你能用一个来源header发出一个获取请求,你的问题就会得到解决,但我不能。
您应该能够通过构建自己的 Request
并将 mode
显式设置为 'cors'
来做到这一点。这是一个例子:
const failingRequest = new Request('https://example.com', {
mode: 'cors'
});
fetch(failingRequest).then(console.log).catch(console.warn);
const successfulRequest = new Request('https://cors-test.appspot.com/test', {
mode: 'cors'
});
fetch(successfulRequest).then(console.log).catch(console.warn);
您应该会看到向 https://example.com
和 https://cors-test.appspot.com/test
发出了 CORS-enabled 请求。第一个请求将失败,因为服务器不支持 CORS,而第二个请求将成功并以 non-opaque Response
object.