先记住这个答案
创建Worker时传入的脚本URL受同源策略约束。同源脚本直接可用;跨域脚本需响应携带Access-Control-Allow-Origin,否则浏览器拒绝创建。同时,脚本不能来自file协议,本地测试需用HTTP服务器。经典脚本和模块脚本的CORS检查一致,但模块脚本还要求正确的MIME类型为JavaScript。Worker的全局作用域不受此影响,但脚本本身加载失败会触发error事件。
- Worker脚本默认须同源,跨域需CORS允许头。
- file://协议一般不能创建Worker,须用HTTP服务。
- 模块Worker还要求MIME正确为JavaScript。
Worker脚本的同源与CORS加载流程
调用new Worker(url)时,浏览器基于页面的源对URL发起请求。若URL同源,请求直接放行;若跨源,则进入CORS流程,要求资源响应头Access-Control-Allow-Origin匹配页面源或为*。缺少该头或值不匹配,浏览器会终止Worker创建并触发error事件。
脚本类型不改变上述规则,但模块脚本额外要求Content-Type为JavaScript MIME(如text/javascript),否则即便CORS通过也会因MIME不匹配加载失败。此外,对跨域请求,浏览器会发送Origin头,服务器需正确回应,否则控制台显示“无法加载”错误。
从CDN加载远程Worker的工程场景
假设站点https://app.example.com需要从https://cdn.example.com/workers/calc.js创建Worker。由于跨源,CDN必须配置Access-Control-Allow-Origin: https://app.example.com或*。代码中写new Worker('https://cdn.example.com/workers/calc.js'),若该头缺失,浏览器拒绝创建并输出CORS报错。
处理方式是在CDN管理后台为资源添加CORS规则,并验证响应头。若无法改动CDN,可将脚本下载到同源目录或通过后端代理转发。生产环境建议使用具体源而非*,以避免后续携带凭证的请求被拒绝。
file协议与嵌套加载的失效边界
file://页面下,即使脚本位于同一本地目录,浏览器也视其为不透明源,通常禁止创建Worker。Chrome和Firefox会在控制台报错,因此本地开发必须通过HTTP服务(如localhost)访问页面。
跨域Worker脚本内若再通过importScripts或ES模块import加载其他脚本,每个子资源请求都必须独立满足同源或CORS规则。如果主脚本已跨域加载,子脚本的同源检查仍基于页面源,而非Worker所在源。此外,no-cors模式不会暴露错误详情,调试需借助服务端日志。
容易答错的地方
- 认为脚本URL可访问就能加载
- 错误。即使URL能被浏览器直接打开,Worker构造器仍强制同源或CORS。若响应头不含允许来源,浏览器会拒绝创建Worker,并报“Script at ... cannot be accessed from origin ...”。
- 混淆模块Worker与经典Worker的CORS差异
- 实际上两者同源限制相同,都是要求CORS头。不同在于模块Worker有额外MIME检查,经典脚本若MIME错误也可能被拒绝,但模块要求更严格。
面试官还会怎么问?
如何在本地快速测试Worker脚本?
使用HTTP服务器,如Python的python -m http.server,通过http://localhost:8000访问页面,避免file://。确保脚本路径与页面同源,否则需配置CORS。
Module Worker跨域需要什么额外的头?
除了Access-Control-Allow-Origin,还要求响应Content-Type是JavaScript的MIME(如text/javascript)。否则即使CORS通过,浏览器也会因MIME类型错误而拒绝加载。
跨域脚本无法改CORS头,是否有其他创建方式?
可以先在主线程用fetch获取脚本文本,再通过URL.createObjectURL生成Blob URL传给Worker。此方式受页面CSP策略限制,且Blob URL仍被视为同源,但需注意CSP的worker-src指令。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。