浏览器接受 "classic" js script-tag,但不接受 ES6 模块——MIME 错误 w/Node http 服务器

Browser accepts "classic" js script-tag, but not ES6 modules — MIME error w/ Node http server

我想玩 ES6 模块,所以我决定使用 Node 作为一个简单的 Web 服务器,以避免我在本地执行时第一次遇到的所有 CORS 相关错误。现在我在浏览器中收到 MIME 类型相关的错误,我不太明白。

这是我的 server.js 文件:

const http = require('http'),
      url  = require('url'),
      fs   = require('fs');

http.createServer((req, res) => {

  const q = url.parse(req.url, true),
        filename = "." + q.pathname;

  fs.readFile(filename, (err, data) => {
    if (err) {
      res.writeHead(404, {'Content-Type': 'text/html'});
      return res.end("404 Not Found");
    }  
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write(data);
    return res.end();
  });

}).listen(8080);

如果我尝试在浏览器中访问我的 index.html 文件,其中包含以下代码:

<!DOCTYPE html>
<html>
<body> 

  <!-- Works -->
  <script src="index.js"></script>

  <!-- Doesn't work -->
  <script src="module.js" type="module"></script>

</body>
</html>

我收到以下错误:

Failed to load module script: The server responded with a non-JavaScript MIME type of "text/html".

type="text/javascript" 属性对模块标签也没有影响。我读到所有 ES6 模块默认都是 "deferred",这意味着它们在 HTML 完全解析之前不会执行。我想这就是问题所在,但我不知道如何相应地修改我的 server.js 文件来修复它。非常感谢您的帮助!如果不是太不切实际,我宁愿不引入任何 NPM 包。

编辑: 我认为自从我访问了 http://localhost:8080/index.html 之后发送类型为 text/html 的 header 是正确的。但是如果我 console.log(url.parse(req.url, true)); 我现在看到延迟脚本标签触发 createServer 回调。 object 记录明确显示它是 JS 模块的文件名。

一旦我修复了错误 header,我会带着一个工作示例回来。

解决方案: 我引入了两个附加模块;路径和 mime。我在 url.parse().

返回的路径的扩展名上使用了 mime.getType()
const http = require('http'),
      url  = require('url'),
      fs   = require('fs'),
      mime = require('mime'),
      path = require('path');

http.createServer((req, res) => {

  const q = url.parse(req.url, true),
        filename = "." + q.pathname;

  fs.readFile(filename, (err, data) => {
    if (err) {
      res.writeHead(404, {'Content-Type': 'text/html'});
      return res.end("404 Not Found");
    }  
    res.writeHead(200, {'Content-Type': mime.getType(path.extname(filename))});
    res.write(data);
    return res.end();
  });

}).listen(8080);
res.writeHead(200, {'Content-Type': 'text/html'});

这表明每个文件都带有 text/html mimetype。

当浏览器请求您的模块时,您将发回 Content-Type: text/html header - 这是无效的,as per the HTML spec:

If any of the following conditions are met, throw a "NetworkError" DOMException:

  • response's type is "error"
  • response's status is not an ok status
  • The result of extracting a MIME type from response's header list is not a JavaScript MIME type

'Classic' 脚本没有这个限制,据我所知。

为了解决这个问题,您需要使用适当的 MIME 类型从服务器发回 JavaScript 模块,例如 text/javascript:

res.writeHead(200, {'Content-Type': 'text/javascript'});

我建议使用类似 Express 的东西,而不是直接使用 http 模块,不过 - you can get a lot of this functionality out of the box,我相信它会处理设置 headers你.