为什么跨源工作人员被阻止,为什么解决方法可以?
Why are cross origin workers blocked and why is the workaround ok?
最近我在 a library 上工作,它支持使用 worker 来完成一些繁重的工作。
我发现,至少在大多数在线代码编辑器 (snippets/jsfiddle/codepen/glitch) 上,我似乎无法从另一个域加载 worker。我收到安全错误(或 firefox 无提示故障)
function startWorker(url) {
try {
const worker = new Worker(url);
console.log('started worker');
worker.onmessage = e => log('black', e.data);
worker.postMessage('Hi from page');
} catch (e) {
console.error('could not start worker:', e);
}
}
const workerURL = 'https://greggman.github.io/doodles/test/ping-worker.js';
startWorker(workerURL);
在 Chrome 和 Safari 中我得到
SecurityError: Failed to construct 'Worker': Script at 'https://greggman.github.io/doodles/test/ping-worker.js' cannot be accessed from origin 'https://...'.
问题 #1:为什么会出现该错误?
是什么设置导致的? iframe 选项?页面的 http headers? http headers 用于 iframe?来自脚本的 http headers?)
问题 #2:有没有办法在 firefox 中检测到这个问题?
我可以从工作人员发送消息并超时,但我想知道是否有一些不那么间接的方法来检查 success/failure
无论如何我都可以通过自己获取脚本文本来解决这个问题
function startWorker(url) {
try {
const worker = new Worker(url);
console.log('started worker');
worker.onmessage = e => console.log(e.data);
worker.postMessage('Hi from page');
} catch (e) {
console.error('could not start worker:', e);
}
}
async function main() {
const workerURL = 'https://greggman.github.io/doodles/test/ping-worker.js';
const res = await fetch(workerURL);
const text = await res.text();
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
startWorker(url);
}
main();
我询问了浏览器团队,他们告诉我手动获取并制作一个 blob url 没问题,这引出了我的 主要问题 。
问题 #3:考虑到解决方法很简单,此安全错误的意义何在?
既然有解决方法,在什么情况下没有解决方法?安全错误的重点是什么?浏览器供应商说我的解决方法很好,实际上我已经使用将事物作为 blob urls 启动的功能使用了 7-8 年。 (html,脚本,但直到现在还没有工作人员)但是如果我的解决方法没问题那么错误的重点是什么?
Question #1: Why do I get that error?
因为这是规范要求的。来自 fetch a classic worker
- Let request be a new request whose url is url, client is fetch client settings object, destination is destination, mode is
"same-origin"
, credentials mode is "same-origin"
, parser metadata is "not parser-inserted"
, and whose use-URL-credentials flag is set.
因此请求将其模式设置为 "same-origin"
,因此,它将失败:
(async ()=>{
const url = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js";
try {
console.log( 'default ("no-cors")' )
await fetch( url )
console.log( 'success' );
}
catch(e) { console.log( 'failed' ); }
try {
console.log( 'like workers ("same-origin")' )
await fetch( url, { mode: "same-origin" } )
console.log( 'success' );
}
catch(e) { console.log( 'failed' ); }
})();
Question #2: Is there a way to detect this issue in firefox?
当然,您只需监听将在您的 Worker 对象上分派的 error
事件:
const url = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
const worker = new Worker( url );
worker.onerror = console.error;
Question #3: What's the point of this security error given the workaround is trival?
因为你的Worker的内部起源要看这个。 ref
Set worker global scope's url to response's url.
因此,如果他们在这里允许“no-cors”请求,您将能够从您的 Worker 获取该服务器上的资源,从而绕过跨域限制。
首先获取它,然后创建一个同源 (blob:URI) 或不透明源 (data:URI )上下文,不存在这个问题。
请注意,只有对 Worker 脚本的初始请求受此限制,因此解决初始问题的另一种方法是使用 中的 importScripts
方法同源 工人:
const worker = new Worker( getURL() );
worker.onmessage = (evt) => console.log(evt.data);
function getURL() {
const txt = document.getElementById( 'source' ).textContent;
return URL.createObjectURL( new Blob( [ txt ] ) );
}
<script id="source" type="worker">
importScripts("https://greggman.github.io/doodles/test/ping-worker.js");
</script>
最近我在 a library 上工作,它支持使用 worker 来完成一些繁重的工作。
我发现,至少在大多数在线代码编辑器 (snippets/jsfiddle/codepen/glitch) 上,我似乎无法从另一个域加载 worker。我收到安全错误(或 firefox 无提示故障)
function startWorker(url) {
try {
const worker = new Worker(url);
console.log('started worker');
worker.onmessage = e => log('black', e.data);
worker.postMessage('Hi from page');
} catch (e) {
console.error('could not start worker:', e);
}
}
const workerURL = 'https://greggman.github.io/doodles/test/ping-worker.js';
startWorker(workerURL);
在 Chrome 和 Safari 中我得到
SecurityError: Failed to construct 'Worker': Script at 'https://greggman.github.io/doodles/test/ping-worker.js' cannot be accessed from origin 'https://...'.
问题 #1:为什么会出现该错误?
是什么设置导致的? iframe 选项?页面的 http headers? http headers 用于 iframe?来自脚本的 http headers?)
问题 #2:有没有办法在 firefox 中检测到这个问题?
我可以从工作人员发送消息并超时,但我想知道是否有一些不那么间接的方法来检查 success/failure
无论如何我都可以通过自己获取脚本文本来解决这个问题
function startWorker(url) {
try {
const worker = new Worker(url);
console.log('started worker');
worker.onmessage = e => console.log(e.data);
worker.postMessage('Hi from page');
} catch (e) {
console.error('could not start worker:', e);
}
}
async function main() {
const workerURL = 'https://greggman.github.io/doodles/test/ping-worker.js';
const res = await fetch(workerURL);
const text = await res.text();
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
startWorker(url);
}
main();
我询问了浏览器团队,他们告诉我手动获取并制作一个 blob url 没问题,这引出了我的 主要问题 。
问题 #3:考虑到解决方法很简单,此安全错误的意义何在?
既然有解决方法,在什么情况下没有解决方法?安全错误的重点是什么?浏览器供应商说我的解决方法很好,实际上我已经使用将事物作为 blob urls 启动的功能使用了 7-8 年。 (html,脚本,但直到现在还没有工作人员)但是如果我的解决方法没问题那么错误的重点是什么?
Question #1: Why do I get that error?
因为这是规范要求的。来自 fetch a classic worker
- Let request be a new request whose url is url, client is fetch client settings object, destination is destination, mode is
"same-origin"
, credentials mode is"same-origin"
, parser metadata is"not parser-inserted"
, and whose use-URL-credentials flag is set.
因此请求将其模式设置为 "same-origin"
,因此,它将失败:
(async ()=>{
const url = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js";
try {
console.log( 'default ("no-cors")' )
await fetch( url )
console.log( 'success' );
}
catch(e) { console.log( 'failed' ); }
try {
console.log( 'like workers ("same-origin")' )
await fetch( url, { mode: "same-origin" } )
console.log( 'success' );
}
catch(e) { console.log( 'failed' ); }
})();
Question #2: Is there a way to detect this issue in firefox?
当然,您只需监听将在您的 Worker 对象上分派的 error
事件:
const url = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
const worker = new Worker( url );
worker.onerror = console.error;
Question #3: What's the point of this security error given the workaround is trival?
因为你的Worker的内部起源要看这个。 ref
Set worker global scope's url to response's url.
因此,如果他们在这里允许“no-cors”请求,您将能够从您的 Worker 获取该服务器上的资源,从而绕过跨域限制。
首先获取它,然后创建一个同源 (blob:URI) 或不透明源 (data:URI )上下文,不存在这个问题。
请注意,只有对 Worker 脚本的初始请求受此限制,因此解决初始问题的另一种方法是使用 中的 importScripts
方法同源 工人:
const worker = new Worker( getURL() );
worker.onmessage = (evt) => console.log(evt.data);
function getURL() {
const txt = document.getElementById( 'source' ).textContent;
return URL.createObjectURL( new Blob( [ txt ] ) );
}
<script id="source" type="worker">
importScripts("https://greggman.github.io/doodles/test/ping-worker.js");
</script>