问题
I want to play with ES6 modules, so I decided on using Node as a simple web server to avoid all CORS related errors I first encountered when doing it locally. Now I get MIME type related errors in the browser which I can't quite grasp.
Here is my server.js
file:
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);
If I try to access my index.html
file in the browser, which contains the following code:
<!DOCTYPE html>
<html>
<body>
<!-- Works -->
<script src="index.js"></script>
<!-- Doesn't work -->
<script src="module.js" type="module"></script>
</body>
</html>
I get the following error:
Failed to load module script: The server responded with a non-JavaScript MIME type of "text/html".
The type="text/javascript"
attribute has no effect on the module tag either. I have read that all ES6 modules are "deferred" by default, meaning that they don't execute before the HTML is fully parsed. I guess this is the problem, but I don't know how to modify my server.js
file accordingly to fix it. Help is greatly appreciated! If not too unpractical, I would prefer not to pull in any NPM packages.
EDIT: I thought that since I accessed http://localhost:8080/index.html
That it was correct to send a header with type text/html
. But if I console.log(url.parse(req.url, true));
I now see that deferred script tags trigger the createServer
callback. The object logged explicitly shows it's the filename of the JS module.
I'll come back with a working example once I've fixed the faulty header.
SOLUTION: I pulled in two additional modules; path and mime. I used mime.getType()
on the extension of the path returned by url.parse()
.
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);
回答1:
res.writeHead(200, {'Content-Type': 'text/html'});
This would suggest that every file is served with a text/html
mimetype.
回答2:
You're sending back a Content-Type: text/html
header when the browser requests your module - this isn't valid, 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' scripts don't have this restriction, as far as I can tell.
In order to fix this, you need to send your JavaScript module back from the server with an appropriate MIME type, such as text/javascript
:
res.writeHead(200, {'Content-Type': 'text/javascript'});
I'd recommend using something like Express instead of working directly with the http
module, though - you can get a lot of this functionality out of the box, and I believe it'll handle setting the headers for you.
来源:https://stackoverflow.com/questions/54651811/browser-accepts-classic-js-script-tag-but-not-es6-modules-mime-error-w-nod