本地文件中的 ES6 module - 服务器以非 JavaScript MIME 类型响应

IT技术 javascript google-chrome ecmascript-6
2021-02-12 08:47:02

我收到此错误:

加载module脚本失败:服务器响应非 JavaScript MIME 类型“”。每个 HTML 规范对module脚本执行严格的 MIME 类型检查。

该项目从本地文件运行,例如:file:///D:/path/project.html.

在 Firefox 中没有问题,但在谷歌浏览器中不起作用。我想以这种方式进行测试以用于开发目的 - 这比创建服务器并记住它在哪个端口上更舒服。

6个回答

对我来说这里没有列出的一个简单的修复是这样的:

我有一个导入语句从不同的文件中引入一个对象,我是通过这一行完成的:

import { Cell } from './modules/Cell';

破坏代码并导致 MIME 类型错误的原因不是没有.js附加到./modules/Cell.

更新后的行解决了我的问题:

import { Cell } from './modules/Cell.js';

JayGould 太棒了!,我对什么都发疯了,这样说是可以理解的。@Jona 对我来说很有意义,天才!,
2021-03-14 08:47:02
哈哈,很高兴你在我偶然发现同样的问题之前找到了它:p
2021-03-16 08:47:02
@Jona 是的,事后看来这是有道理的,但我想弄清楚这一点我已经疯了。
2021-03-17 08:47:02
哇。对。就在这儿。也有道理,因为这明确告诉它导入module是什么类型
2021-03-20 08:47:02
谢天谢地,浏览器控制台给了我一个有用的错误消息,所以我不需要花一个小时来找到这个解决方案。不是!顺便说一句,我使用的是 HTTP 服务器(Python2)。
2021-03-22 08:47:02

如果您看到此错误消息,则表示这不是同源问题。

正如错误消息中所说,真正的问题是module脚本要求脚本文件的 MIME 是 javascript MIME 类型之一。

您的文件系统不提供任何 MIME,因此加载失败。

所以最好的解决方案显然是在本地服务器上运行你的代码,而不是在文件系统上。

但既然你坚持;)一种解决方法是首先使用 XHR 将你的脚本文件作为 Blob 获取(fetch不能用于file://协议),然后强制其type属性成为 js MIME 之一,并将你<script>的 src 设置为 blobURI指向这个 Blob。

// requires to start chrome with the --allow-file-access-from-file flag
var xhr = new XMLHttpRequest();
xhr.onload = e => {
    let blob = xhr.response;
    blob.type = 'application/javascript'; // force the MIME
    moduleScript.src = URL.createObjectURL(blob);
};
xhr.open('get', "yourmodule.js");
xhr.responseType = 'blob';
xhr.send();

但是,您将无法import从您的module中获得任何依赖项。

如果您在本地服务器上运行它,但仍然遇到此问题怎么办?
2021-03-18 08:47:02
我有一个零导入的module,所以这应该可以工作。但由于 CORS 策略,它仍然无法加载脚本:Access to XMLHttpRequest at 'file:///Users/test.js' from origin 'null' has been blocked by CORS policy
2021-03-20 08:47:02
这对解决方法没有真正的帮助,但值得称赞。在其他情况下可以派上用场......
2021-03-28 08:47:02
@TomášZato 请注意,在这种情况下,可能可以通过chrome脚本(扩展)强制 MIME,使用webRequest API,但我不知道它足以说明如何进行...
2021-04-07 08:47:02

ES6 module文件使用浏览器强制执行标准同源策略限制加载,并具有许多其他安全限制,而 JavaScript“脚本”文件具有更宽松的安全性,以避免破坏现有网站,因为浏览器已添加更好的安全标准随着时间的推移。您正在点击其中之一,即必须使用正确的 MIME 类型发送文件。

file://URL 不是普通的 HTTP 请求,因此它们对请求有不同的规则。对于应该发送什么 MIME 类型也几乎没有规则。如果你想使用 ES6 module,那么你需要在本地运行一个真正的 HTTP 服务器来为你的文件提供服务。

我在询问可能的开发标志/选项,以使我能够在没有服务器的情况下测试文件。
2021-03-14 08:47:02
我正在运行 python 的 SimpleHTTPServer。为什么这还不够?
2021-03-16 08:47:02
我不相信你除了运行服务器之外别无选择。
2021-04-03 08:47:02

您可以设置ModuleSpecifierdata URI

<script type="module">
  import {Test} from "data:application/javascript,const%20Mod={this.abc=123};export%20{Mod};";
  console.log(Test);
</script>

要以ModuleSpecifier编程方式设置,您可以使用--allow-file-access-from-files标志启动 Chromium/Chrome并利用XMLHttpRequest()file:协议请求 JavaScript 文件

<script>
(async() => {

  const requestModule = ({url, dataURL = true}) => 
    new Promise((resolve, reject) => {
      const request = new XMLHttpRequest();
      const reader = new FileReader();
      reader.onload = () => { resolve(reader.result) };
      request.open("GET", url);
      request.responseType = "blob";
      request.onload = () => { reader[dataURL ? "readAsDataURL" : "readAsText"](request.response) };
      request.send();
   })

  let moduleName = `Mod`;
  // get `Mod` module
  let moduleRequest = await requestModule({url:"exports.js"});
  // do stuff with `Mod`; e.g., `console.log(Mod)`
  let moduleBody = await requestModule({url:"ModBody.js", dataURL: false}); 
  let scriptModule = `import {${moduleName}} from "${moduleRequest}"; ${moduleBody}`;
  let script = document.createElement("script");
  script.type = "module";
  script.textContent = scriptModule;
  document.body.appendChild(script);

})();
</script>

在 Windows 上,我无法正确加载 ES 2016 module。即使您禁用了安全性,您也会遇到下一个问题,即 .js 文件没有设置 MIME 类型,因此您会收到类似 Failed to load module script: The server responded with a non-JavaScript MIME 这样的消息类型 ””。每个 HTML 规范对module脚本执行严格的 MIME 类型检查。

答案是在macintosh上使用Safari,它允许本地文件与ES 2016module没有问题。有趣的是,Chrome 和 Firefox 也无法正常工作。坦率地说,这是一个错误,因为当您加载本地文件时,从同一文件夹访问文件绝对没有任何不安全之处。但祝 Google 或 Firefox 能够解决这个问题。Apple 甚至在他们的下拉菜单中有一个关于跨脚本权限的标志,所以他们知道禁用无意义的安全内容是多么重要。