使用http模块创建Node.js服务器时,如何加载外部CSS/JS/图片?
原生Node.js HTTP服务器加载静态资源404问题解决
问题场景
使用原生http模块结合if语句处理路由时,浏览器加载外部CSS文件返回404错误,但改用Express路由则能正常加载。错误代码如下:
const http = require('http'); const url = require('url'); const fs = require('fs'); const path = require('path'); const express = require('express'); const app = express(); const home = fs.readFileSync(`${__dirname}/pages/home.html`, 'utf-8'); const style = app.use(express.static(path.join(__dirname, '/public'))); const server = http.createServer((req, res) => { const pathName = req.url; if (pathName === '/' || pathName === '/home') { res.writeHead(200, { 'Content-type': 'text/html', }); res.end(home); } else { res.writeHead(404, { 'Content-type': 'text/html', }); res.end("<h1>Who's there ? </h1>"); } }); server.listen(3333, '127.0.0.1', () => { console.log('are you working on 3333?'); });
正常加载的Express参考代码:
const fs = require('fs'); const url = require('url'); const express = require('express'); const path = require('path'); const app = express(); app.use(express.static(__dirname + '/public')); const termen = path.join(__dirname + '/pages/home.html'); app.get('/', function (req, res) { res.sendFile(termen); }); app.listen(3333); console.log('hai');
问题原因
你在原生http服务器中引入了Express的express.static,但该中间件只适用于Express的请求处理流程,原生http服务器并不会识别它。同时,当前的路由逻辑将所有非/、/home的请求直接返回404,包括CSS等静态资源的请求。
修改方案
直接在原生http的请求处理逻辑中添加静态资源处理分支,读取对应文件并返回:
const http = require('http'); const url = require('url'); const fs = require('fs'); const path = require('path'); const home = fs.readFileSync(`${__dirname}/pages/home.html`, 'utf-8'); const publicDir = path.join(__dirname, 'public'); // 定义常见资源的Content-Type映射,确保浏览器正确解析资源 const mimeTypes = { '.html': 'text/html', '.css': 'text/css', '.js': 'text/javascript', '.png': 'image/png', '.jpg': 'image/jpeg', '.gif': 'image/gif' }; const server = http.createServer((req, res) => { const pathName = req.url; if (pathName === '/' || pathName === '/home') { res.writeHead(200, { 'Content-type': 'text/html', }); res.end(home); } else { // 处理静态资源请求 const filePath = path.join(publicDir, pathName); const ext = path.extname(filePath); // 检查文件是否存在 fs.access(filePath, fs.constants.F_OK, (err) => { if (err) { // 文件不存在返回404 res.writeHead(404, { 'Content-type': 'text/html' }); res.end("<h1>Who's there ? </h1>"); return; } // 根据文件后缀设置正确的Content-Type const contentType = mimeTypes[ext] || 'application/octet-stream'; res.writeHead(200, { 'Content-type': contentType }); // 流式读取文件并返回,比同步读取更高效 fs.createReadStream(filePath).pipe(res); }); } }); server.listen(3333, '127.0.0.1', () => { console.log('are you working on 3333?'); });
关键改动说明
- 移除无用的Express依赖,纯原生实现静态资源处理
- 添加
mimeTypes对象,根据文件后缀设置对应Content-Type,避免浏览器无法识别资源类型 - 对非首页请求,优先检查是否为public目录下的有效文件,存在则返回文件内容,不存在才返回404
- 使用
fs.createReadStream流式读取文件,相比同步读取更适合处理大文件,性能更优
内容的提问来源于stack exchange,提问作者Corneliu Grozavu
相关产品推荐
相关产品推荐

