从 0 到 1 入门 Node.js:手把手教你搭建简易 HTTP 服务器​

328 阅读3分钟

在前端开发越来越追求全栈能力的今天,Node.js 凭借其轻量高效的特点,成为众多开发者的心头好。它让 JavaScript 不仅能运行在浏览器中,还能在服务器端大展拳脚。今天,我们就一起从零开始,走进 Node.js 的世界,亲手搭建一个简易的 HTTP 服务器!​

基础知识

1. Node.js 基础

  • 核心模块

    • http:创建 HTTP 服务器(处理请求和响应)。
    • fs:文件系统操作(读取文件、写入文件等)。
    • path:处理文件路径(避免不同系统路径分隔符差异)。
  • 模块化方案

    • CommonJS(老方案):使用 require('模块名') 引入模块(如 const http = require('http'))。
    • ES6 Modules(新方案):使用 import 模块 from '模块名'(需在 package.json 中添加 "type": "module" 或使用 .mjs 后缀)。

2. HTTP 服务器

  • 创建服务器

    const server = http.createServer((req, res) => {
      // 处理请求和响应
    });
    server.listen(1234); // 监听 1234 端口
    
  • 请求与响应

    • req(请求对象):包含 method(请求方法)、url(请求路径)等信息。

    • res(响应对象):

      • res.writeHead(statusCode, headers):设置响应状态码和头部。
      • res.end(content):结束响应并返回内容。

3. 路由基础

  • 路径匹配:根据 req.url 处理不同请求(如首页、CSS、JS 文件)。

    if (req.method === 'GET' && req.url === '/') {
      // 处理首页请求
    } else if (req.url === '/index.html') {
      // 处理 HTML 请求
    }else if (req.url === '/style.css') {
      // 处理 CSS 请求
    }else if (req.url === '/script.js') {
      // 处理 javaScript 请求
    

4. 文件系统操作

  • 异步读取文件

准备几个文件:

image.png

fs.readFile(path.join(__dirname, 'public', 'index.html'), (err, content) => {
  if (err) {
    res.writeHead(500);
    res.end('Server Error');
    return;
  }
  res.writeHead(200, { 'Content-Type': 'text/html' });
  res.end(content);
});
  • path.join():拼接路径(如 __dirname表示项目根路径/public/index.html)。
  • Content-Type:根据文件类型设置响应头(如 text/htmltext/css)。

5. 端口与网络基础

  • 端口作用:区分同一设备上的不同服务(如 3306 对应 MySQL,80 对应 HTTP)。
  • URL 结构协议://域名:端口/路径(如 http://localhost:1234/style.css)。
  • 本地开发:使用 localhost(域名)或 127.0.0.1(IP 地址)访问本地服务。

6. 错误处理

  • 服务器错误
    • 500 状态码:服务器内部错误(如文件读取失败)。
    • 404 状态码:资源未找到(代码中未处理,需自行添加)。

7. 现代模块化实践

  • ES6 Modules 启用方式
    1. 使用 .mjs 后缀文件。

注意:node 最新版本22 支持

image.png

实战

image.png

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./style.css"> 
    <!-- 记得引入css文件 -->
</head>
<body>
    <h1>Cookie</h1>
    <!-- 记得引入js文件 -->
    <script src="./script.js"></script>
</body>
</html>
*{
    margin: 0;
    padding: 0;
}
body{
    background-color: green;
    width: 100vw;
    height: 100vh;
}
console.log("hhhhh")
const http = require('http'); // 引入核心模块
const fs = require('fs'); // 文件系统模块 file system
const path = require('path'); // 路径模块 path
const server = http.createServer((req, res) => { 
    if(req.method=='GET' && (req.url=='/' || req.url=='/index.html')){ // 首页
        fs.readFile(path.join(__dirname,'public','index.html'),(err,content)=>{
            if(err){
                res.writeHead(500);
                res.end('Server Error');
                return;
            }
            res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); // 响应头
            res.end(content); // 响应体
        })
    }
    // http://localhost:1234/style.css
    if(req.method=='GET'&& req.url=='/style.css'){
        fs.readFile(path.join(__dirname,'public','style.css'),(err,content)=>{
            if(err){
                res.writeHead(500);
                res.end('Server Error');
                return;
            }
            res.writeHead(200,{'Content-Type':'text/css;charset=utf-8'});
            res.end(content);
        })
    }
    if(req.method=='GET'&& req.url=='/script.js'){
        fs.readFile(path.join(__dirname,'public','script.js'),(err,content)=>{
            if(err){
                res.writeHead(500);
                res.end('Server Error');
                return;
            }
            res.writeHead(200,{'Content-Type':'text/javascript;charset=utf-8'});
            res.end(content);
        })
    }
}); 

server.listen(1234); // 监听端口

image.png

image.png

image.png

如果我把路径的文件名故意写错,看看会发生什么

//改成style1.css
fs.readFile(path.join(__dirname,'public','style1.css'),(err,content)=>{
                if(err){
                    res.writeHead(500);
                    res.end('Server Error');
                    return;
                }
                res.writeHead(200,{'Content-Type':'text/css;charset=utf-8'});
                res.end(content);
            })

image.png

报错500

常见问题与避坑指南​

  1. 端口占用:如果 1234 端口被占用,可以换一个端口(如 8080 )。​
  1. 响应头设置错误:例如返回 HTML 却设置 Content-Type: 'text/plain' ,会导致浏览器无法正确解析内容。​
  1. 文件路径错误:使用 path.join() 拼接路径,确保兼容性,同时检查文件是否存在。