无法使用位于其他域的 JS 工作文件构建“工作人员”

Posted

技术标签:

【中文标题】无法使用位于其他域的 JS 工作文件构建“工作人员”【英文标题】:Getting Failed to construct 'Worker' with JS worker file located on other domain 【发布时间】:2020-01-25 16:33:32 【问题描述】:

我正在使用react-pdf 在我的 Django/Wagtail 网站上内嵌呈现 PDF 文件。

为此,我在我的 html 模板中创建了一个 ID 为 react 的 div,并运行了一个名为 index.js 的文件,这是一个非常简单的 React 文件,它创建一个 DocumentViewer 元素并使用 ReactDom 将其渲染到 div id '反应'。

从我的主包加载工作文件时,在生产环境中运行我的网站时出现错误,特别是有关如何无法从源“example.com”访问脚本 worker.js 的错误

确切的代码并不真正相关(尽管我可以在必要时发布它,但给我带来问题的是加载 react-pdf 工作程序。

我使用以下导入语句作为the docs recommend:

import Document, Outline, Page from 'react-pdf/dist/entry.webpack';

然后我使用 webpack 来打包和缩小这个文件,使用下面的webpack.config.js:

var path = require("path");
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');

module.exports = 
  context: __dirname,

  entry: './project/app_name/static/js/index.js',

  output: 
      path: path.resolve('./project/app_name/static/bundles/'),
      publicPath: '/static/bundles/',
      filename: "[name]-[hash].js",
  ,

  plugins: [
    new BundleTracker(filename: './webpack-stats.json'),
  ],
  module: 
    rules: [
      
        test: /\.js$/,
        exclude: /node_modules/,
        use: ['babel-loader']
      
    ]
  ,
  resolve: 
    extensions: ['*', '.js', '.jsx']
  

;

这会在我的 Django 应用程序的 static/bundles 文件夹中创建两个文件,main-<hash>.js<hash>.worker.js

main-<hash>.js 文件创建一个这样的工作者:

return new Worker(r.p+"<hash>.worker.js")

当我在本地机器上运行我的 Django 安装时,我从本地主机提供静态文件没有问题,这是非常合乎逻辑的,因为所有文件都具有相同的来源。

但是,当我在生产环境中运行它时,我从 DigitalOcean 空间提供静态文件,Chrome 会产生以下错误:

main-.js:38 未捕获的 DOMException:无法构造“Worker”: 脚本在 'https://ams3.digitaloceanspaces.com/-media/static/bundles/.worker.js' 无法从源“https://www.example.com”访问。

我已经检查了该空间上的 CORS 标头,一切似乎都井井有条。

当我像这样使用 curl 命令时:

curl -v 'https://ams3.digitaloceanspaces.com/<project>-media/static/bundles/<hash>.worker.js' -X OPTIONS -H "Origin:https://example.com" -H "Access-Control-Request-Method: GET,PUT,HEAD,POST"

我得到 200 OK 响应。

我不知道为什么 Chrome 会拒绝加载这个脚本。

我的 webpack 配置、CORS 设置或浏览器处理加载我缺少的外部脚本的任何其他方式中是否缺少某些内容?

【问题讨论】:

“Script at ... cannot be access from origin ...” 不是 CORS 错误消息。我不知道它实际上是那种错误,但事实并非如此浏览器在 CORS 错误消息中使用的措辞。 我认为这是另外一回事。有关详细信息,在 Safari 中访问该站点时,我收到以下错误消息:“SecurityError: The operation is insecure.” Firefox 不会发出警告,但也不会加载 PDF。 搜索其他 SO 问题和答案时,似乎浏览器通常会报告 “Script at ... cannot be access from origin ...” 错误消息,当您尝试加载工作人员时从file:/// URL 而不是从实际的 Web 服务器加载它。(或者可能是相反的方式 - 您正在从 file:/// URL 加载文档,但该文档正试图从某些网络服务器。) 我之前也看到过这个答案,但它绝对不是从file:/// url 加载的。这就是让我困惑的地方。 【参考方案1】:

对于阅读本文的任何人:我弄清楚了问题所在。

大多数浏览器都不允许您从外部源加载 Worker,即使 CORS 标头都是有序的,脚本加载是从与 Worker 相同的源加载的,并且源在我的控制之下。

Chrome、Firefox 和 Safari 都给出了不同的错误,这就是为什么我对到底发生了什么感到困惑。

我解决这个问题的方法是不加载外部工作人员,而是内联运行代码。

解决此问题的其他两种方法是:

提供与网页同源的 worker.js 文件。 通过 blob URL 创建工作程序(如在this link 中)。 我使用的 worker 是从依赖项中的包加载的,我尝试将 Webpack 配置为像这样加载这个 worker,但我无法让它工作。

所以最后我选择了根本不加载工人。

【讨论】:

【参考方案2】:

支持带有 blob URL 的 CROS worker,你可以这样做:

function workerCros(url) 
  const iss = "importScripts('" + url + "');";
  return URL.createObjectURL(new Blob([iss]));


const workerUrl = workerCros(new URL(workerFilePath, window.location).href);
const worker = new Worker(workerUrl);

【讨论】:

以上是关于无法使用位于其他域的 JS 工作文件构建“工作人员”的主要内容,如果未能解决你的问题,请参考以下文章

当我在 gunicorn 中为 Django 应用程序设置工作人员超时时,其他用户无法访问该应用程序

无法访问 Node.js 中的其他文件

使用 Workday API 编辑工作人员附加数据

处理由并行工作人员生成的日志文件的工具(例如,通过构建系统)

Beanstalkd 在伪造队列工作人员上同时运行队列中的所有作业

更新域的hosts文件[关闭]