🎯 第 14 课(续):返回 HTML、CSS、JS 和图片等静态资源

3 阅读3分钟

📌 核心知识点
服务器不仅要处理动态请求(如 /login ),还要能提供静态文件(HTML、CSS、JS、图片等)。我们将学会如何用 Node.js 原生方式服务这些“静态资源”。


🧱 什么是静态资源?

文件类型示例路径
HTML 页面/index.html
CSS 样式表/style.css
JavaScript 文件/app.js
图片/logo.png, /bg.jpg
字体、图标等/icon.svg

👉 这些文件内容是“固定的”,不需要每次计算,直接读取并返回即可。


📁 先准备项目结构

修改你的项目目录如下:

my-web-app/
├── server.js          ← 主服务器
├── public/            ← 所有静态文件放这里
│   ├── index.html
│   ├── style.css
│   ├── script.js
│   └── logo.png       ← (可以随便放一张图片命名为此)

💡 public/ 是前端资源的标准存放文件夹名称。


✅ 步骤一:创建 public/index.html

<!-- public/index.html -->
<!DOCTYPE html>
<html>
<head>
  <title>我的 Node.js 网站</title>
  <link rel="stylesheet" href="/style.css">
</head>
<body>
  <h1>🎉 欢迎来到我的网站</h1>
  <p class="intro">这是由纯 Node.js 提供的页面,连样式都是它给的!</p>
  <img src="/logo.png" alt="Logo" width="200">
  <button onclick="sayHello()">点我试试</button>
  <script src="/script.js"></script>
</body>
</html>

✅ 步骤二:创建 public/style.css

/* public/style.css */
body {
  font-family: Arial, sans-serif;
  text-align: center;
  margin-top: 50px;
  background-color: #f0f8ff;
}

h1 {
  color: #2e8b57;
}

.intro {
  color: #4682b4;
  font-size: 1.2em;
}

button {
  padding: 10px 20px;
  font-size: 1em;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

✅ 步骤三:创建 public/script.js

// public/script.js
function sayHello() {
  alert('Hello from Node.js server!');
}

✅ 步骤四:更新 server.js 支持静态文件

我们现在要实现:

  • 如果请求的是 /style.css → 返回 CSS 文件
  • 如果是 /script.js → 返回 JS 文件
  • /logo.png → 返回图片(二进制)

🔧 关键点:根据文件扩展名设置正确的 Content-Type

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

// MIME 类型映射(告诉浏览器文件是什么格式)
const mimeTypes = {
  '.html': 'text/html',
  '.css': 'text/css',
  '.js': 'application/javascript',
  '.png': 'image/png',
  '.jpg': 'image/jpeg',
  '.gif': 'image/gif',
  '.json': 'application/json'
};

const server = http.createServer((req, res) => {
  const parsedUrl = url.parse(req.url);
  let pathname = parsedUrl.pathname;

  // 默认首页
  if (pathname === '/') {
    pathname = '/index.html';
  }

  // 构造本地文件路径
  const filePath = path.join(__dirname, 'public', pathname);

  // 获取文件扩展名
  const extname = path.extname(filePath).toLowerCase();
  const contentType = mimeTypes[extname] || 'application/octet-stream'; // 默认为二进制流

  // 尝试读取文件
  fs.readFile(filePath, (err, content) => {
    if (err) {
      if (err.code === 'ENOENT') {
        // 文件不存在
        res.writeHead(404, { 'Content-Type': 'text/plain' });
        res.end('404 - 页面未找到');
      } else {
        // 其他错误(如权限问题)
        res.writeHead(500, { 'Content-Type': 'text/plain' });
        res.end('500 - 服务器内部错误');
      }
    } else {
      // 成功读取文件
      res.writeHead(200, { 'Content-Type': contentType + '; charset=utf-8' });
      res.end(content);
    }
  });
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(`✅ 静态服务器已启动:http://localhost:${PORT}`);
});

🏃‍♂️ 测试步骤

  1. 确保所有文件已创建
  2. 启动服务器:
node server.js
  1. 打开浏览器访问:
    👉 http://localhost:3000

你应该看到:

  • 美观的标题和文字
  • 背景颜色
  • 显示图片
  • 可点击按钮弹出提示

🎉 恭喜!你已经用原生 Node.js 实现了一个能提供完整网页体验的服务器!


✅ 本课小结一句话:

使用 fs.readFile + path.join + MIME type 映射,可以让 Node.js 服务器正确返回 HTML、CSS、JS、图片等静态资源,打造真正可用的网站。


🚨 注意事项

  • 生产环境不会用这种方式服务静态文件(性能不够好),而是用 Nginx 或 Express 的 express.static()
  • 但我们通过手动实现,彻底理解了“静态资源服务”的原理,这非常重要!

📬 下一课预告:
第 15 课:实战项目② —— 构建一个“天气查询”API 接口!

我们将结合前面所学,做一个真实的 API:

  • 接收城市名
  • 返回模拟天气数据
  • 支持 JSON 格式