【问题标题】:Chrome can't load web workerChrome 无法加载网络工作者
【发布时间】:2014-02-19 22:10:09
【问题描述】:

我正在做一个使用网络工作者的项目。

在我的头部分我有这个代码:

var worker = new Worker("worker.js");
// More code

这在 Safari 中运行良好,但 Chrome 报告以下错误:

Uncaught SecurityError: Failed to create a worker: script at '(path)/worker.js' cannot be accessed from origin 'null'.

为什么这在 Safari 中可以完美运行,但在 Chrome 中却不行?我该如何解决这个问题?

谢谢。

【问题讨论】:

  • 您是否在使用文件协议?如果您设置了访问标志并查看它是否有效:*.com/questions/18586921/…
  • 是的,web worker 的路径是这样的:file:///E:/programming/web/project/worker.js。主项目的路径是这样的:file:///E:/programming/web/project/index.html.

标签: javascript google-chrome web-worker


【解决方案1】:

要在使用 Webpack 和 TypeScript 设置的项目中从文件加载 web worker,我使用了 Tomáš Zato 建议的脚本。但是,我不得不修改工作文件。

worker.ts

(() => {
    console.log("worker_function loaded");
    // @ts-ignore
    window.worker_function = () => {
        self.onmessage = ({ data: { question } }) => {
            // @ts-ignore
            self.postMessage({
                answer: 42,
            });
        };
    }
})();

index.ts

async function run() {
    console.log('run()');

    const worker = new Worker(
        // @ts-ignore
        URL.createObjectURL(new Blob(["("+worker_function.toString()+")()"], { type: 'text/javascript' }))
    );

    worker.postMessage({
        question: 'The Answer to the Ultimate Question of Life, The Universe, and Everything.',
    });
    worker.onmessage = ({ data: { answer } }) => {
        console.log(answer);
    };
}

run();

index.html

<html lang="en-us">
  <head>
    <meta charset="utf-8" />
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
    <title>Offscreen canvas with web worker sample project</title>
    <script async type="text/javascript" src="worker.js"></script>
    <script async type="text/javascript" src="app.js"></script>
  </head>
  <body>
    <h1>web worker sample project</h1>
  </body>
</html>

webpack.config.js(版本 5)

const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");

module.exports = {
  mode: "production",
  entry: {
    app: "./src/index.ts",
    worker: "/src/worker.ts"
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "build")
  },
  performance: {
    hints: false
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: "ts-loader",
        exclude: /node_modules/
      },
    ]
  },
  resolve: {
    extensions: [".js", ".ts"]
  },
  plugins: [
    new CopyPlugin({
      patterns: [
        { from: "src/index.html", to: "" }
      ]
    })
  ]
};

【讨论】:

    【解决方案2】:

    这是受上面 Thomas 回答的启发。但有一点需要注意的是 我只想分发 HTML,所以我 manually converted the js to dataURL。并启用其中的数据 URL 复选框。

    const myWorker = new Worker("data:application/x-javascript;base64,b25tZXNzYW...");

    【讨论】:

      【解决方案3】:

      在 chrome 中制作 本地 http 服务器的简单方法是这个应用程序:

      Chrome 网络服务器

      https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb/related

      说明:

      Chrome 的 Web 服务器,使用 HTTP 通过网络从本地文件夹提供网页。离线运行。 Web Server for Chrome 是用于 Chrome 的开源 (MIT) HTTP 服务器。

      它可以在您安装了 Chrome 的任何地方运行,因此您可以随身携带。它甚至适用于 ARM chromebook。

      它现在可以选择在本地网络上侦听,以便其他计算机可以访问您的文件。此外,它还可以尝试获取 Internet 地址。

      许多人使用它在 chromebook 上进行基本的 Web 开发。它还可以方便地在计算机之间通过本地网络共享文件,甚至在 Internet 上共享文件。

      安装后,导航到http://127.0.0.1:8887

      而且它不是不安全的标志 --allow-file-access-from-files

      【讨论】:

      • 这太棒了!我现在可以使用本地文件系统中的网络工作者运行我的 reactJS 应用程序。再简单不过了!
      【解决方案4】:
      function worker_fun(num){
          num ++
          // console.log(num)
          postMessage(num);
          setTimeout(worker_fun.bind(null,num), 500)
      }
      
      var w
      
      function startWorker(){
          var blob = new Blob([
              "onmessage = function(e){\
                  " + worker_fun.toString() + "\
                  worker_fun(e.data.num);}"
          ]);
          var blobURL = window.URL.createObjectURL(blob);
          if (typeof(Worker) != 'undefined'){
              if (typeof(w) == 'undefined'){
      
                  w = new Worker(blobURL);
                  w.onmessage = function(event){
                      document.getElementById('num').innerHTML = event.data;
                  } 
                  w.postMessage({
                     num:parseInt(document.getElementById('num').innerHTML)})
              }
          }
      }
      
      
      function stopWorker() { 
          w.terminate();
          w = undefined;
      }
      

      如前所述,chrome 不支持它。我喜欢在同一个文件中定义我的工人。这是一个可行的解决方法,它将每 500 毫秒增加一个在元素的 innerHTML 中找到的数字,id=num

      【讨论】:

        【解决方案5】:

        Chrome 不允许您在从本地文件运行脚本时加载网络工作者。

        【讨论】:

        • 来自this answer, Loading a local file, even with a relative URL, is the same as loading a file with the file: protocol. -- 网页能够随意访问您的文件系统并不酷。
        • -1 firsfox 当然会让您这样做,前提是您使用文件作为来源(例如,您正在浏览器中查看本地文件)。只是铬坏了。
        • Firefox 仍然可以工作(来自 file://),Chrome 在这种情况下不能工作。
        • 有许多变通方法,例如在 chrome 设置中设置标志,使用本地服务器而不是直接访问 html 或注入 worker。
        【解决方案6】:

        我使用了一种解决方法。铬块 Worker 但不是 &lt;script&gt;。因此,制定通用解决方案的最佳方法是:

        function worker_function() {
            // all code here
        }
        // This is in case of normal worker start
        // "window" is not defined in web worker
        // so if you load this file directly using `new Worker`
        // the worker code will still execute properly
        if(window!=self)
          worker_function();
        

        然后你像往常一样链接它&lt;script src="..."。一旦定义了函数,您就可以使用这种可憎的代码:

        new Worker(URL.createObjectURL(new Blob(["("+worker_function.toString()+")()"], {type: 'text/javascript'})));
        

        【讨论】:

        • 这个解决方案很好。为什么在这个世界上没有什么是完美的?每个软件都在用错误、缺陷、幼稚行为等来激怒用户。Firefox 也很傲慢,因为它拒绝支持“clip-path”css 属性。
        • 我不是一个 js 开发者,并且不明白这里使用的脚本标签的意义。什么是窗口!= 自检?有人可以解释一下这个加载顺序吗?谢谢。
        • @treeseal7 应该在 web worker 上下文中执行的代码。
        • 我应该注意,你不能使用这样写的工人的 importScript。至少,并非没有额外的解决方法。所以你需要对多文件工作者进行更多的篡改。
        • 我也注意到了这一点,但是 stringify 变量要传递 (json) var json = JSON.stringify(xJsonArgs); 而不是像 new Worker(URL.createObjectURL(new Blob([(${xFunction.toString()})( ${json})], { type: 'text/javascript' }))); 为我工作。感谢您的回复。
        【解决方案7】:

        另一种解决方法是使用 Google 的 web server for Chrome 扩展名。选择您的工作目录并启动服务器,完成!

        【讨论】:

          【解决方案8】:

          是的,如果您正在加载本地文件,它将无法在 chorome 中工作。但它会在Firefox浏览器中正常工作。您必须在 HTML 文件中添加以下代码。

          <head>
              <meta charset="UTF-8" />
          </head>
          

          【讨论】:

            【解决方案9】:

            我也遇到了和你的帖子一样的问题。解决方案是您必须使用 localhost(wamp 或 xamp)运行它。会搞定的。

            【讨论】:

            • 哇,我永远找不到这个——谢谢! (我希望在 cmets 中允许感谢)
            【解决方案10】:

            这是因为安全限制。您需要使用http://https:// 协议而不是file:///

            如果您安装了 NodeJS,您可以简单地执行以下操作。 - 请注意,这是许多可用选项之一

            安装local-web-server

            $ npm install -g local-web-server
            

            现在您可以在任何您想通过http访问内容的文件夹中使用它。

            $ ws
            

            导航到http://localhost:8000(默认端口:8000)

            【讨论】:

              【解决方案11】:

              一个可能的原因是 chrome 在从本地文件运行脚本时不允许您加载网络工作者。我尝试在我的 Firefox 上运行代码,也不能。

              【讨论】:

              • Web Workers 在 Firefox 51.0.1 中的 file:// 上运行良好
              【解决方案12】:

              您还可以在启动 Chrome 时使用 --allow-file-access-from-files 标志。

              MacOsX 示例:

              /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --allow-file-access-from-files
              

              更多信息:Web worker settings for chrome

              【讨论】:

              • 在 windows 命令窗口导航到:“C:\Users\NAME\AppData\Local\Google\Chrome SxS\Application”,然后运行 ​​chrome.exe --allow-file-access-from-文件,然后复制您的本地文件路径,例如c:\temp\myWeb\index.html 并粘贴到打开的浏览器的 url 中,完成。
              • 也可以创建快捷方式,并在目标路径中传递标志。
              • 哦,从链接的问题中,记得在使用标志启动之前关闭所有 Chrome 窗口。
              • 是的,另一个选项也可以是在其清单中编写具有正确权限的 Chrome 扩展程序:"permissions": ["file://*/*"],如 *.com/questions/19493020/…
              • 注意:“您必须先关闭 Chrome 的所有窗口,然后才能打开 --allow-file-access-from-files 标志。”如*.com/a/21771754/325418 所述
              【解决方案13】:

              Chrome 加载文件但无法运行。使用Firefox。它对我有用。

              【讨论】:

              • 解释我的反对意见:最好从评论开始,也许更多地询问他们的浏览器支持要求,而不是作为答案提交。鉴于用户已经说过有关跨浏览器支持的内容,这似乎很可能不是答案。
              • 如果您仔细阅读了这个问题,我相信您不会在投票之前将回复投票为三!用户说 Chrome 无法加载工作人员。不,chrome 可以加载 worker 但不能运行它。我之所以把它作为回应,首先是一年前提出的问题,其次是许多回应说 Firefox 没有运行工作程序,我无法对所有这些问题发表评论。我只是在解释,但你有权投反对票或投赞成票。
              【解决方案14】:

              由于 Python 2.x 比 Python 3.x 更广泛地部署,python -m SimpleHTTPServer 8000 之类的东西更普遍适用,而不仅仅是 Mac OS X。我发现它在 Cygwin 下使用是必要的。

              有了这个,this example 就像一个冠军一样工作。

              【讨论】:

                【解决方案15】:

                您需要一个 Web 服务器来接收来自 HTTP 协议的请求,而不是本地文件 并正常工作:)

                【讨论】:

                • 不,你没有。你需要忽略那些不遵循网络标准的浏览器,因为它们是主流。
                【解决方案16】:

                Noble Chicken 已经正确解释了这个问题,但我有一个更通用的解决方案。无需安装 wamp 或 xamp,您可以使用 python 导航到项目所在的文件夹并输入:python -m http.server

                就这样,您将在该文件夹上拥有一个正在运行的服务器,可从 localhost 访问。

                【讨论】:

                • Mac 可能需要使用 python -m SimpleHTTPServer 8000,因为它们已加载
                • 您也可以安装 http-server 节点模块,然后从终端导航到所需的文件夹并运行“http-server -p 3000”。
                • 值得一提的是这个脚本“python -m http.server”需要Python 3。
                • 也可以试试php -S localhost:8000
                最近更新 更多