如何解决Node.js服务返回text/html MIME类型导致JS模块加载失败问题
错误根因
- 你当前写的Node服务对所有请求统一返回index.html文件,且固定设置
Content-Type为text/html。当浏览器请求src/js/main.js这个JS模块时,拿到的是HTML内容,MIME类型不匹配,直接触发规范要求的严格校验报错。 - 还有个隐藏问题:yahoo-finance2的服务端能力不能直接在浏览器端运行,你现在把yahoo-finance2的调用写在前端main.js里,就算解决了MIME问题也无法正常获取数据,必须把这部分逻辑移到服务端做代理接口。
具体修复步骤
第一步:修改server.js 支持静态资源返回与API代理
import * as http from "http"; import * as fs from "fs"; import * as path from "path"; import yahooFinance from "yahoo-finance2"; const hostname = "127.0.0.1"; const port = 3000; // 配置不同后缀对应的MIME类型 const mimeTypes = { '.html': 'text/html', '.js': 'application/javascript', '.css': 'text/css', '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml' }; const server = http.createServer(async function (req, res) { // 处理股票数据API代理请求 if (req.url.startsWith('/api/historical')) { const urlParams = new URL(req.url, `http://${hostname}:${port}`); const symbol = urlParams.searchParams.get('symbol'); const start = urlParams.searchParams.get('start'); const end = urlParams.searchParams.get('end'); const interval = urlParams.searchParams.get('interval'); try { const queryOptions = { period1: new Date(start), period2: new Date(end), interval: interval, }; const result = await yahooFinance.historical(symbol, queryOptions); const resultWithSymbol = result.map(item => ({ ...item, symbol })); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(resultWithSymbol)); } catch (err) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: err.message })); } return; } // 处理静态资源请求 let filePath = '.' + req.url; if (filePath === './') { filePath = './index.html'; } const extname = String(path.extname(filePath)).toLowerCase(); const contentType = mimeTypes[extname] || 'application/octet-stream'; fs.readFile(filePath, (error, content) => { if (error) { if(error.code === 'ENOENT') { res.writeHead(404, { 'Content-Type': 'text/html' }); res.end('Whoops! File not found!', 'utf-8'); } else { res.writeHead(500); res.end('Server Error: ' + error.code, 'utf-8'); } } else { res.writeHead(200, { 'Content-Type': contentType }); res.end(content, 'utf-8'); } }); }); server.listen(port, hostname, function (error) { if (error) { console.log("Something went wrong", error); } else { console.log("Server running at http://" + hostname + ":" + port + "/"); } });
第二步:修改前端main.js 移除服务端包引用,改为调用本地接口
async function api(symbol, start, end, val) { try { // 调用自己的Node服务代理接口 const response = await fetch(`/api/historical?symbol=${symbol}&start=${start}&end=${end}&interval=${val}`); const resultWithSymbol = await response.json(); console.log(resultWithSymbol); return resultWithSymbol; } catch (err) { console.error('请求失败:', err); } } api("TSLA", "2021-08-02", "2021-08-14", "1d");
第三步:调整文件路径
如果你的index.html放在src目录下,需要把server.js里的静态资源根目录调整为./src;或者先执行npm run build打包项目,再把server.js里的静态资源路径改为./dist,直接serve打包后的产物。
运行方式
执行npm run start启动服务,访问http://127.0.0.1:3000即可正常加载资源、获取股票数据。
内容的提问来源于stack exchange,提问作者user139442
相关产品推荐
相关产品推荐

