我想玩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>
我得到以下错误:
加载模块脚本失败:服务器以非JavaScript MIME类型的"text/html"。
type="text/javascript"
属性对模块标记也没有影响。我读到所有ES6模块默认情况下都是"延迟"的,这意味着它们在HTML完全解析之前不会执行。我想这就是问题所在,但我不知道如何相应地修改我的server.js
文件来修复它。非常感谢您的帮助!如果不是太不切实际,我宁愿不拉任何NPM包。
编辑:由于我访问了http://localhost:8080/index.html
,我认为发送类型为text/html
的标头是正确的。但是如果我console.log(url.parse(req.url, true));
,我现在看到延迟的脚本标记触发createServer
回调。记录的对象明确显示它是JS模块的文件名。
一旦我修复了有故障的标头,我将返回一个工作示例。
解决方案:我增加了两个模块;path和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
标头-根据HTML规范,这是无效的:
如果满足以下任何条件,则抛出"NetworkError"DOMException:
- 响应的类型为"
error
">- 响应的状态不是正常状态
- 从响应的标头列表中提取MIME类型的结果不是JavaScript MIME类型
据我所知,"经典"脚本没有这个限制。
为了解决这个问题,您需要使用适当的MIME类型从服务器发回JavaScript模块,例如text/javascript
:
res.writeHead(200, {'Content-Type': 'text/javascript'});
不过,我建议您使用Express之类的东西,而不是直接使用http
模块——您可以开箱即用地获得很多功能,我相信它会为您设置标题。