Node.js 后端开发入门:从模块系统到 HTTP 服务搭建

0 阅读10分钟

前言

Node.js 作为 JavaScript 的运行时环境,在前端开发中已经占据了重要地位。但它的能力远不止于此,在后端开发领域同样表现出色。本文将介绍 Node.js 的模块系统,探讨 HTTP 协议基础,并通过一个完整的后端 Demo 展示如何用 Node.js 快速搭建 Web 服务。


与传统的后端语言的区别

Node.js 作为后端和传统 Java/PHP 这类后端相比,就像快餐车和大酒楼的区别。Node.js 轻便灵活,用前端熟悉的 JavaScript 就能快速搭起服务,特别适合中小型项目和实时应用;传统后端则像正规军,需要更多配置(比如 Java 的 Tomcat),但更适合处理复杂业务。简单说:想快速上线选 Node.js,要稳健可靠选传统后端,现在很多项目干脆让它们搭档干活——Node.js 处理接口和实时通信,传统后端负责核心业务!


node.js

接下来通过展现制作一个node.js的后端js代码(名为server.js)的过程,来给大家讲讲node.js是如何创建服务器工作!

Node.js 的 HTTP 服务

在 Node.js 中,我们可以使用内置的 http 模块轻松创建一个 Web 服务器。

那么如何引入这个内置的http呢,需要使用模块化引入。

Node.js 提供了两种模块化方案:

  1. CommonJS (require) :Node.js 早期采用的模块化方案
  2. ES Modules (import) :ES6 引入的更先进的模块化方案

1.使用了 CommonJS 的 require 语法来引入http模块:

const http = require('http');

这是一种更古老的、原始的引用方式,如上所示,直接使用require关键字引入即可,可以在require()里面输入需要引入的模块,从而得到该模块对象。

2.使用ES6 Modules的import语法来引入http模块:

import http from 'http';

使用ES6新推出的import引入模块同样可以得到一个对象,注意,使用这种语法引入模块的方式需要在.mjs的文件中才能成功运行,.mjs 是 Node.js 中用于标识 ECMAScript 模块(ES Modules)的文件扩展名,当文件使用 import/export 语法时必须使用.mjs扩展名。

(.mjs才能运行import是长久以来的规定,有些node高版本可能会支持在.js的文件也能成功运行)

在本文的案例中,我们使用CommonJS 的 require 语法的这种语法来引入吧,大家可以随意选择!因为后面都是对这个对象进行操作,跟引入的方式关系不大

文件和路径模块

该案例除了需要引入http这个核心模块,我们还需要fs(fileSystem文件模块)和path(path路径模块)的帮助,才能帮我们完成这个服务器的创建,同样咱们统一用require方式引入。

const fs = require('fs'); // file system 
const path = require('path') // 路径模块

HTTP 协议基础

引入了http这个核心模块之后,我们就要开始操作这个http对象了,不过在此之前请允许我向你介绍一下http的一些协议基础。 (了解过http的大佬可以跳过这一部分)

IP 地址与端口

  • IP 地址:标识网络中的某台设备(如 127.0.0.1 表示本地)
  • 端口:标识设备上的特定服务(如 3306 通常用于 MySQL 服务)

在计算机网络中,IP地址和端口号共同构成了网络通信的基础定位系统。IP地址就像一栋大楼的门牌号,它唯一标识了网络中的某台设备(如服务器、个人电脑等)。而端口号则像是大楼里的房间号,它指定了设备上运行的特定服务。以MySQL数据库为例,它默认使用3306端口,这意味着当客户端要连接MySQL服务时,不仅要指定服务器的IP地址,还要指明3306这个"房间号"。

每个端口号背后都对应着一个正在运行的服务进程。当请求到达服务器时,操作系统会根据端口号将请求分发给对应的服务进程处理。比如Web服务通常使用80(HTTP)或443(HTTPS)端口,邮件服务可能使用25(SMTP)或110(POP3)端口。这种设计使得一台设备可以同时运行多个网络服务而互不干扰,就像一栋大楼里可以同时有多个办公室各自运作一样。

端口号的范围是0-65535,其中0-1023是公认端口(Well-Known Ports),通常分配给系统级服务使用;1024-49151是注册端口,用于用户级服务;49152-65535是动态/私有端口,供临时使用。理解IP地址和端口的关系,是掌握网络编程和服务器配置的重要基础。

请求与响应

请求组成

  1. 请求行

    • 方法:GET(获取)、POST(提交)、PUT(更新)、DELETE(删除)等
    • URL:统一资源定位符(协议://域名:端口/路径?查询参数#片段)
    • HTTP版本:HTTP/1.1 或 HTTP/2
  2. 请求头

    • Host:目标主机
    • User-Agent:客户端信息
    • Accept:可接受的响应类型
    • Content-Type:请求体的媒体类型(如 application/json
  3. 请求体(可选):

    • POST/PUT 请求通常包含
    • 可以是表单数据、JSON、XML等格式

响应组成

  1. 状态行

    • HTTP版本
    • 状态码:200(成功)、404(未找到)、500(服务器错误)等
    • 状态文本
  2. 响应头

    • Content-Type:响应体的媒体类型
    • Content-Length:响应体大小
    • Set-Cookie:设置客户端cookie
  3. 响应体

    • 请求的资源或处理结果
    • 可能是HTML、JSON、二进制数据等

状态码分类

  • 1xx(信息性):请求已被接收,继续处理

  • 2xx(成功):

    • 200 OK:标准成功响应
    • 201 Created:资源创建成功
    • 204 No Content:成功但无返回内容
  • 3xx(重定向):

    • 301 Moved Permanently:永久重定向
    • 302 Found:临时重定向
    • 304 Not Modified:资源未修改(缓存相关)
  • 4xx(客户端错误):

    • 400 Bad Request:请求语法错误
    • 401 Unauthorized:需要认证
    • 403 Forbidden:服务器拒绝请求
    • 404 Not Found:资源不存在
  • 5xx(服务器错误):

    • 500 Internal Server Error:通用服务器错误
    • 502 Bad Gateway:网关/代理错误
    • 503 Service Unavailable:服务不可用

创建服务

接下来就是正式利用http对象创建一个web服务器了: 让我们补充server.js和index.html

image.png

//server.js
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' })
      res.end(content);
    })
  }
})
server.listen(8080);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>哈哈</h1>
</body>
</html>

此刻我们用node启动刚刚书写的server.js,然后浏览器访问localhost:8080即可看到我们所书写的html代码了,意味着我们已经用node创建了一个本地的服务器了

可以看到在终端用node启动时,不会输出任何内容,则是启动成功了 image.png

访问localhost:8080则可以成功看到我们服务器返回的内容(index.html) image.png

让我们来解读上面的server.js代码:

// 引入必要的Node.js核心模块
const http = require('http');  // HTTP模块,用于创建web服务器
const fs = require('fs');      // 文件系统模块,用于文件读写操作
const path = require('path');  // 路径处理模块,用于安全地处理文件路径

// 创建HTTP服务器实例
const server = http.createServer((req, res) => {
  /*
   * 请求处理逻辑
   * req: 请求对象,包含客户端请求的信息
   * res: 响应对象,用于向客户端返回数据
   */
  
  // 检查请求方法和URL路径
  // 只处理GET请求,并且URL是根路径/或/index.html
  if (req.method == 'GET' && (req.url == '/' || req.url == '/index.html')) {
    
    // 使用path.join安全地拼接文件路径
    // __dirname表示当前文件所在目录
    // 'public'是子目录,'index.html'是目标文件
    const filePath = path.join(__dirname, 'public', 'index.html');
    
    // 异步读取文件内容
    fs.readFile(filePath, (err, content) => {
      // 错误处理回调
      if (err) {
        // 如果读取文件出错,返回500服务器错误状态码
        res.writeHead(500); 
        // 结束响应并返回错误信息
        res.end('Server error');
        return; // 提前返回,不再执行后续代码
      }
      
      // 成功读取文件后:
      // 1. 设置响应状态码200(成功)和Content-Type头
      res.writeHead(200, { 'Content-Type': 'text/html' });
      
      // 2. 将文件内容作为响应体发送
      res.end(content);
    });
  }
});

server.listen(8080); //监听8080端口
/*
 * 代码解读:
 * 1. 模块引入部分:
 *    - http: 创建web服务器的核心模块
 *    - fs: 用于读取本地文件
 *    - path: 安全地处理文件路径,避免不同操作系统的路径差异问题
 * 
 * 2. 服务器创建部分:
 *    - 使用http.createServer()方法创建服务器实例
 *    - 传入的回调函数会在每次收到请求时执行
 * 
 * 3. 请求处理逻辑:
 *    - 首先检查请求方法和路径,只处理特定的GET请求
 *    - 使用path.join()安全拼接路径,比字符串拼接更可靠
 *    - fs.readFile()异步读取文件内容
 *    - 完善的错误处理:文件读取失败返回500错误
 *    - 成功读取后设置正确的Content-Type并返回文件内容
 * 
 * 4. 注意事项:
 *    - 这是一个基础实现,实际应用中需要考虑更多情况:
 *      * 其他HTTP方法的处理
 *      * 其他URL路径的处理
 *      * 更完善的错误处理
 *      * 静态资源缓存等性能优化
 *    - 目前代码只能处理index.html,实际需要支持多种静态文件
 */

它的特点如下:

  1. 模块化设计:合理使用Node.js核心模块(http, fs, path)各司其职
  2. 安全路径处理:使用path.join()代替字符串拼接,避免跨平台问题
  3. 基本路由功能:通过判断req.url实现简单路由
  4. 错误处理机制:对文件读取操作进行了错误处理
  5. 正确的Content-Type设置:确保浏览器能正确解析HTML内容

总结

本文详细介绍了如何使用 Node.js 的核心模块(httpfspath)构建一个简单的静态文件服务器,并深入解析了代码的关键部分。以下是核心要点总结:

  1. 核心模块的作用

    • http:用于创建 Web 服务器,处理 HTTP 请求和响应。
    • fs:提供文件系统操作,如读取 HTML 文件。
    • path:安全地拼接路径,避免跨平台兼容性问题(如 Windows 和 Linux 的路径分隔符差异)。
  2. 服务器基本逻辑

    • 使用 http.createServer() 创建服务器,监听请求。
    • 检查请求方法(GET)和路径(/ 或 /index.html)。
    • 使用 fs.readFile() 异步读取文件,并返回给客户端。
  3. 关键细节

    • 路径处理:使用 path.join(__dirname, 'public', 'index.html') 确保路径正确。
    • 错误处理:文件读取失败时返回 500 状态码,防止服务器崩溃。
    • 响应头设置:正确设置 Content-Type: text/html,让浏览器正确解析 HTML。
  4. 扩展方向

    • 支持更多文件类型(如 CSS、JS、图片)。
    • 添加 404 处理,优化错误提示。
    • 引入流(fs.createReadStream)提升大文件传输性能。

本文的代码虽然简单,但涵盖了 Node.js Web 开发的核心概念,是学习后端开发的重要基础。理解这些内容后,可以进一步学习 Express、Koa 等框架,构建更强大的 Web 应用。