Node.js 作为基于 V8 引擎的 JavaScript 运行环境,打破了 JavaScript 仅能在浏览器端运行的局限,让其能够处理服务器端的输入输出、网络请求和数据库操作等任务,成为前端工程化、服务端开发、跨端应用开发的核心技术之一。本文基于相关技术文档梳理,涵盖 Node.js 基础概念、核心特性、常用模块、开发部署及运维监控,补充完整可运行的实践代码,兼顾知识点的系统性与实操性,既适合入门学习,也可作为后续复习、日常开发的参考文档,助力快速掌握 Node.js 从基础到企业级实践的全流程。

Node.js 介绍

什么是 Node.js

Node.js 是基于 Chrome V8 JavaScript 引擎构建的服务器端 JavaScript 运行环境,并非编程语言或框架。它允许开发者使用 JavaScript 编写服务器端代码,实现传统后端语言(如 Java 、 Python )所能完成的功能,包括处理 HTTP 请求、操作文件系统、读写数据库、实现网络通信等。

image-20260209185346116

Node.js 的底层架构由多个核心部分组成,从上层到下层依次为:用户代码、 Node.js 核心( JavaScript 层)、 N-API 、 Node.js 核心( C++层),以及依赖的第三方库( V8 、 libuv 、 OpenSSL 、 zlib 等)。其中 V8 引擎负责解析和执行 JavaScript 代码, libuv 负责处理异步 I/O 操作和事件循环,确保 Node.js 具备高效的并发处理能力。

应用场景

image-20260209185405758

Node.js 的应用场景广泛,尤其适合处理高并发、 I/O 密集型任务,结合企业级实践,核心应用场景主要包括以下几类:

服务端应用开发,可用于构建 API 接口、数据聚合层( BFF 层)、微服务等。在企业实践中, Node.js 常作为数据聚合层,接收前端请求后,整合多个后端服务的数据,统一返回给前端,减少前端与后端的交互次数,提升页面加载效率。

前端工程化工具集,这是 Node.js 最普及的应用场景。前端开发中的依赖管理、代码转译、打包构建、代码校验、测试等工具,均基于 Node.js 开发。例如依赖管理工具 npm 、 yarn 、 pnpm ; JavaScript 转译工具 Babel ;打包构建工具 Webpack 、 Vite 、 Rollup ; CSS 后处理工具 PostCSS 、 Sass ;代码校验工具 ESLint 、 Prettier ;测试工具 Jest 、 Playwright 等,这些工具极大提升了前端开发效率和代码质量。

服务端渲染( SSR ),通过 Node.js 在服务器端渲染页面,生成完整的 HTML 内容后返回给前端,既解决了单页应用( SPA ) SEO 优化困难的问题,也能提升页面首屏加载速度,尤其适合内容型网站、电商网站等对 SEO 和加载速度有要求的场景。

跨平台桌面应用开发,借助 Electron 等基于 Node.js 的框架,可使用 JavaScript 、 HTML 、 CSS 开发跨平台的桌面应用,一套代码可适配 Windows 、 Mac 、 Linux 等操作系统。例如 Visual Studio Code 、企业内部员工 IM 工具等,均是基于 Node.js 相关技术开发。

Node.js 基础知识

安装与 npm 使用

Node.js 的安装与 npm 的使用是入门的基础,步骤简单且标准化,具体操作如下:

安装 Node.js ,访问 Node.js 官方网站,根据自身操作系统( Windows 、 Mac 、 Linux )下载对应的安装包,按照安装向导完成安装即可。建议下载 LTS 版本(长期支持版本),稳定性更高,适合开发和生产环境使用。

检查安装是否成功,安装完成后,打开命令行终端,输入 node -v ,若安装成功,会输出 Node.js 的版本号;输入 npm -v ,会输出 npm 的版本号( npm 已随 Node.js 默认安装,无需单独安装)。

npm 核心使用方法, npm 是 Node.js 的包管理器,用于下载、管理、更新项目所需的第三方模块,核心命令如下:

  1. npm install 模块名:安装指定模块,默认安装到当前项目的 node_modules 目录下,若加上-g 参数,则全局安装,可在任意项目中使用。
  2. npm uninstall 模块名:卸载指定模块,移除 node_modules 目录下对应的模块文件和依赖记录。
  3. npm update 模块名:更新指定模块到最新版本,若不指定模块名,则更新项目中所有依赖模块。
  4. npm search 模块名:搜索 npm 仓库中的指定模块,查看模块的基本信息和版本。
  5. npm init :初始化一个新的 Node.js 项目,生成 package.json 文件,该文件用于记录项目信息、依赖模块、脚本命令等。
  6. npm publish :将自己开发的模块发布到 npm 仓库,供其他开发者下载使用(需先注册 npm 账号并登录)。

核心特性

Node.js 之所以能够广泛应用,得益于其独特的核心特性,这些特性使其在处理高并发、 I/O 密集型任务时具备明显优势:

单线程, Node.js 采用单线程模型,整个应用只有一个主线程,所有 JavaScript 代码都在这个主线程中执行。单线程模型避免了多线程之间的线程切换开销,提升了执行效率,同时也简化了代码编写,无需处理多线程同步问题。但需要注意,单线程模型下,若执行耗时的同步操作,会阻塞整个应用的运行,因此 Node.js 中应尽量避免同步 I/O 操作,优先使用异步操作。

image-20260209185449100

异步非阻塞 I/O ,这是 Node.js 最核心的特性。 Node.js 中的 I/O 操作(如文件读写、网络请求、数据库操作等)均为异步非阻塞模式,当发起一个 I/O 操作后,主线程不会等待操作完成,而是继续执行后续代码,当 I/O 操作完成后,会通过事件通知的方式,将结果反馈给主线程,由主线程处理后续逻辑。这种模式让 Node.js 能够同时处理大量的 I/O 请求,提升了应用的并发处理能力和吞吐量。

事件驱动, Node.js 基于事件驱动的编程模式,整个应用的运行依赖于事件的触发和处理。 Node.js 内置事件循环机制,用于监听事件、分发事件,当某个事件触发时,对应的事件处理器(回调函数)会被执行。例如, I/O 操作完成后会触发完成事件, HTTP 服务器收到请求后会触发请求事件,这种模式让代码逻辑更清晰,也更适合异步编程场景。

模块化, Node.js 支持模块化编程,将应用程序分解为独立的、可重用的组件(模块),每个模块负责特定的功能,提升了代码的可读性、可维护性和可重用性。 Node.js 中的模块分为核心模块、第三方模块和自定义模块三类,同时支持 CommonJS 和 ES6 两种模块规范。

跨平台, Node.js 可运行在 Windows 、 Mac 、 Linux 等多种操作系统上,实现“一次编写,多端运行”,无需针对不同操作系统修改代码,降低了开发和维护成本。

异步编程

异步编程是 Node.js 的核心编程范式,用于处理 I/O 操作和其他异步任务,避免阻塞主线程,提升应用的响应性能和吞吐量。 Node.js 中常用的异步编程处理方式有四种:

回调函数,这是最基础、最原始的异步处理方式,将一个函数作为参数传递给异步操作,当异步操作完成后,回调函数会被调用,用于处理返回结果或错误信息。示例如下(文件读取异步操作):

1
2
3
4
5
6
7
8
9
10
11
const fs = require('fs');
// 异步读取文件,回调函数处理结果
fs.readFile('./test.txt', 'utf8', (err, data) => {
if (err) {
console.error('文件读取失败:', err.message);
return;
}
console.log('文件内容:', data);
});
// 异步操作不会阻塞后续代码执行
console.log('正在读取文件...');

需要注意,过多的回调函数嵌套会导致“回调地狱”,使代码可读性和可维护性变差,因此在实际开发中,尽量避免多层回调嵌套,可使用 Promise 、 async/await 替代。

Promise , Promise 是 ES6 中引入的异步编程解决方案,用于解决回调地狱问题。 Promise 是一个代表异步操作最终完成或失败的对象,有三种状态: pending (进行中)、 fulfilled (已成功)、 rejected (已失败),状态一旦改变,就不会再变化。示例如下(基于 Promise 的文件读取):

1
2
3
4
5
6
7
8
9
10
const fs = require('fs/promises');
// 基于Promise的异步读取文件
fs.readFile('./test.txt', 'utf8')
.then((data) => {
console.log('文件内容:', data);
})
.catch((err) => {
console.error('文件读取失败:', err.message);
});
console.log('正在读取文件...');

Promise 支持链式调用,可将多个异步操作按顺序串联起来,代码逻辑更清晰,避免了回调嵌套。

async/await , async/await 是 ES7 中引入的异步编程语法,基于 Promise 实现,能够以同步代码的写法编写异步操作,进一步简化了异步编程的代码,提升了可读性。使用 async 关键字修饰函数,函数内部可使用 await 关键字等待 Promise 对象的结果, await 只能在 async 函数中使用。示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
const fs = require('fs/promises');
// async/await异步读取文件
async function readFileAsync() {
try {
console.log('正在读取文件...');
const data = await fs.readFile('./test.txt', 'utf8');
console.log('文件内容:', data);
} catch (err) {
console.error('文件读取失败:', err.message);
}
}
// 调用async函数
readFileAsync();

事件监听,结合 Node.js 的事件驱动特性,通过事件监听的方式处理异步操作。使用 events 模块创建事件发射器,绑定事件处理器,当异步操作完成后,触发对应的事件,执行事件处理器。示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const EventEmitter = require('events');
// 创建事件发射器实例
const emitter = new EventEmitter();

// 绑定事件处理器(监听事件)
emitter.on('readFileSuccess', (data) => {
console.log('文件读取成功,内容:', data);
});

emitter.on('readFileError', (err) => {
console.error('文件读取失败:', err);
});

// 异步读取文件,完成后触发对应事件
const fs = require('fs');
fs.readFile('./test.txt', 'utf8', (err, data) => {
if (err) {
emitter.emit('readFileError', err.message);
return;
}
emitter.emit('readFileSuccess', data);
});

模块化编程

模块化编程是一种软件设计模式,将应用程序分解为独立的、可重用的组件(模块),每个模块负责特定的功能,避免代码冗余,提升代码的可读性、可维护性和可重用性。

模块类型, Node.js 中的模块主要分为三类:

  1. 核心模块: Node.js 自带的模块,无需安装,可直接通过 require 引入使用,例如 fs (文件系统)、 http ( HTTP 服务器)、 path (路径处理)、 os (操作系统)等。
  2. 第三方模块:由第三方开发者创建并发布到 npm 仓库的模块,需通过 npm 安装后,才能引入使用,例如 express ( Web 框架)、 axios ( HTTP 请求工具)等。
  3. 自定义模块:开发者根据项目需求编写的模块,可在项目内部复用,需通过相对路径引入使用。

模块规范, Node.js 支持两种模块规范,分别是 CommonJS 规范和 ES6 模块规范,两种规范的用法有所不同:

CommonJS 规范, Node.js 默认采用的模块规范,核心用法如下:

  • 导出模块:使用 module.exports 或 exports 导出模块中的变量、函数、对象等。
  • 引入模块:使用 require 函数引入模块, require 的参数为模块路径(核心模块直接写模块名,自定义模块写相对路径,第三方模块写模块名)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 模块A(moduleA.js),导出模块
const message = 'Hello Node.js';
const printMessage = () => {
console.log(message);
};
// 导出单个变量
module.exports = message;
// 导出多个内容
// module.exports = {
// message,
// printMessage
// };

// 模块B(moduleB.js),引入模块
const message = require('./moduleA'); // 引入自定义模块
const fs = require('fs'); // 引入核心模块
console.log(message); // 输出:Hello Node.js

ES6 模块规范, ES6 引入的模块化规范,目前 Node.js 已支持该规范,使用时需在 package.json 中添加”type”: “module”配置,核心用法如下:

  • 导出模块:使用 export default (默认导出,一个模块只能有一个默认导出)或 export (按需导出,可导出多个)。
  • 引入模块:使用 import 关键字引入模块, import 的参数为模块路径,需添加.js 后缀( CommonJS 规范可省略)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 模块A(moduleA.js),导出模块
const message = 'Hello Node.js';
const printMessage = () => {
console.log(message);
};
// 默认导出
export default message;
// 按需导出
// export { message, printMessage };

// 模块B(moduleB.js),引入模块
import message from './moduleA.js'; // 引入默认导出
// import { message, printMessage } from './moduleA.js'; // 引入按需导出
console.log(message); // 输出:Hello Node.js

Node.js 核心模块

Node.js 的核心模块是开发的基础,每个核心模块都有特定的功能,掌握常用核心模块的用法,能够快速实现各类基础功能。以下梳理常用核心模块的功能及实践示例,补充完善实操细节,确保可直接运行。

常用核心模块汇总

fs:文件系统模块,用于处理文件相关的操作,包括文件的创建、读取、写入、重命名、删除、更改权限等,支持同步和异步两种操作方式,推荐优先使用异步操作,避免阻塞主线程。

http: HTTP 服务器模块,用于创建 HTTP 服务器,处理 HTTP 请求和响应,包括监听端口、解析请求参数、路由处理、响应数据等,是构建 API 接口、 Web 服务的基础。

path:路径模块,提供了处理文件路径的各类方法,包括路径拼接、路径解析、获取文件名、获取文件后缀名等,解决不同操作系统路径分隔符不一致的问题。

os:操作系统模块,提供一些与操作系统相关的方法,包括获取操作系统信息(如系统类型、版本)、获取内存使用情况、获取 CPU 信息、处理路径分隔符等。

events:事件模块,用于实现事件驱动的编程模式,提供了事件发射器类( EventEmitter ),可实现事件的绑定、触发、解绑等操作,是 Node.js 异步编程的核心基础。

querystring:查询字符串模块,用于解析和格式化 URL 查询字符串,例如将查询字符串转换为对象,或将对象转换为查询字符串。

url: URL 模块,用于解析和格式化 URL ,包括获取 URL 的协议、主机名、路径、查询参数、哈希值等,简化 URL 相关的处理操作。

stream:流模块,用于处理流数据,实现数据的流式传输和处理,例如大文件读取、数据压缩、加密解密等,流操作可节省内存,提升处理效率。

核心模块实践示例

fs 模块(文件系统)

fs 模块支持同步和异步操作,以下提供异步操作的实践示例(推荐使用),包括文件读取、文件写入、文件追加、文件删除等常用操作:

文件读写实践,读取指定文件的内容,修改后重新写入文件,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const { readFile, writeFile } = require('fs/promises');
const path = require('path');

// 异步读写文件(结合async/await,简化代码)
async function updateFile() {
try {
// 拼接文件路径(使用path.resolve确保路径正确,适配不同操作系统)
const filePath = path.resolve('./package.json');
// 读取文件,指定编码格式为utf8,避免返回Buffer对象
const contents = await readFile(filePath, { encoding: 'utf8' });
// 将读取的JSON字符串转换为对象
const data = JSON.parse(contents);
// 修改文件内容(例如修改项目名称)
data.name = 'nodejs-demo';
// 写入文件,JSON.stringify第三个参数用于格式化输出,提升可读性
await writeFile(filePath, JSON.stringify(data, null, 4), 'utf8');
console.log('文件更新成功');
} catch (err) {
// 捕获异常,输出错误信息
console.error('文件操作失败:', err.message);
}
}

// 调用函数,执行文件读写操作
updateFile();

文件追加与删除,向指定文件追加内容,删除指定文件,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const { appendFile, unlink } = require('fs/promises');
const path = require('path');

// 向文件追加内容
async function appendToFile() {
try {
const filePath = path.resolve('./test.txt');
// 追加内容,若文件不存在则自动创建
await appendFile(filePath, '\n追加的内容', 'utf8');
console.log('内容追加成功');
} catch (err) {
console.error('追加内容失败:', err.message);
}
}

// 删除文件
async function deleteFile() {
try {
const filePath = path.resolve('./test.txt');
await unlink(filePath);
console.log('文件删除成功');
} catch (err) {
console.error('文件删除失败:', err.message);
}
}

// 执行操作
appendToFile().then(() => {
// 追加完成后,删除文件
setTimeout(deleteFile, 3000);
});

http 模块( HTTP 服务器)

http 模块用于创建 HTTP 服务器,处理前端请求并返回响应,以下提供两个核心实践示例:创建基础 HTTP 服务器、发起 HTTP 请求。

创建基础 HTTP 服务器,监听指定端口,接收前端 GET 请求,返回响应数据,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const http = require('http');

// 定义服务器地址和端口
const hostname = '127.0.0.1';
const port = 3000;

// 创建HTTP服务器,回调函数处理请求和响应
const server = http.createServer((req, res) => {
// 设置响应状态码(200表示成功)
res.statusCode = 200;
// 设置响应头,指定内容类型为纯文本,编码为utf8
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
// 设置允许跨域(可选,用于前端请求)
res.setHeader('Access-Control-Allow-Origin', '*');
// 返回响应内容,结束响应
res.end('Hello Node.js! 这是一个基础HTTP服务器');
});

// 服务器监听指定端口和地址
server.listen(port, hostname, () => {
console.log(`服务器运行在 http://${hostname}:${port}/`);
});

运行代码后,打开浏览器访问http://127.0.0.1:3000,即可看到响应内容;也可使用Postman、curl等工具发起GET请求,获取响应。

发起 HTTP 请求,向第三方 API 接口发起 GET 请求,获取响应数据,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const http = require('http');

// 定义请求配置
const options = {
hostname: 'api.example.com', // 目标服务器地址
path: '/endpoint', // 请求路径
method: 'GET', // 请求方法
headers: {
'Content-Type': 'application/json' // 请求头
}
};

// 发起HTTP请求
const req = http.request(options, (res) => {
// 监听响应数据,拼接数据(响应数据可能分块返回)
let data = '';
res.on('data', (chunk) => {
data += chunk;
});

// 响应结束后,处理数据
res.on('end', () => {
console.log('响应状态码:', res.statusCode);
console.log('响应数据:', data);
});
});

// 监听请求错误,处理异常
req.on('error', (error) => {
console.error('请求失败:', error.message);
});

// 结束请求(必须调用,否则请求无法发送)
req.end();

path 模块(路径处理)

path 模块用于处理文件路径,解决不同操作系统路径分隔符( Windows 使用\, Mac 、 Linux 使用/)不一致的问题,常用方法实践示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const path = require('path');

// 1. 拼接路径(最常用,自动适配操作系统分隔符)
const path1 = path.resolve(__dirname, 'src', 'index.js');
console.log('拼接路径:', path1); // 输出:当前文件所在目录/src/index.js

// 2. 解析路径,获取路径的各个部分
const parsedPath = path.parse(path1);
console.log('解析路径:', parsedPath);
// 输出:{ root: '/', dir: '/xxx/xxx/src', base: 'index.js', ext: '.js', name: 'index' }

// 3. 获取文件后缀名
const extname = path.extname(path1);
console.log('文件后缀名:', extname); // 输出:.js

// 4. 获取文件名(不带后缀)
const filename = path.basename(path1, extname);
console.log('文件名(不带后缀):', filename); // 输出:index

// 5. 获取文件所在目录
const dirname = path.dirname(path1);
console.log('文件所在目录:', dirname); // 输出:当前文件所在目录/src

// 6. 判断路径是否为绝对路径
const isAbsolute = path.isAbsolute(path1);
console.log('是否为绝对路径:', isAbsolute); // 输出:true

events 模块(事件处理)

events 模块的核心是 EventEmitter 类,用于实现事件的绑定、触发、解绑,实践示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const EventEmitter = require('events');

// 1. 创建EventEmitter实例
const emitter = new EventEmitter();

// 2. 绑定事件(on方法,可绑定多个同类型事件)
// 绑定click事件
emitter.on('click', (data) => {
console.log('click事件触发1,数据:', data);
});

// 绑定click事件(多个处理器按绑定顺序执行)
emitter.on('click', (data) => {
console.log('click事件触发2,数据:', data);
});

// 3. 触发事件(emit方法,可传递参数)
emitter.emit('click', 'Hello Events');

// 4. 绑定一次性事件(once方法,触发一次后自动解绑)
emitter.once('onceEvent', () => {
console.log('一次性事件触发');
});
emitter.emit('onceEvent'); // 触发一次,输出内容
emitter.emit('onceEvent'); // 再次触发,无响应

// 5. 解绑事件(off方法,需指定事件名和对应的处理器)
const handleMouseMove = (data) => {
console.log('mousemove事件触发:', data);
};
emitter.on('mousemove', handleMouseMove);
emitter.emit('mousemove', '移动了'); // 触发事件,输出内容
emitter.off('mousemove', handleMouseMove); // 解绑事件
emitter.emit('mousemove', '移动了'); // 解绑后,无响应

// 6. 监听所有事件(newListener方法,绑定事件时触发)
emitter.on('newListener', (eventName, listener) => {
console.log(`正在绑定${eventName}事件`);
});
emitter.on('test', () => {}); // 绑定test事件,触发newListener

企业级核心中间件与服务

在企业级 Node.js 开发中,除了原生核心模块,还会用到一系列内部封装的核心中间件和服务,用于提升开发效率、保障系统稳定性和可维护性。结合企业实践,核心中间件与服务包括:

核心中间件,用于处理请求拦截、响应处理、日志记录、权限校验等通用逻辑,统一封装后,可在所有接口中复用。

调用服务,包括 SOA Client 、 DAL Client 等,用于对接企业内部的微服务、数据库等,实现数据的读写和服务的调用。

监控服务,包括日志记录( TripLog )、链路追踪( BAT )、指标监控( Dashboard )等,用于实时监控应用的运行状态,快速定位问题。

缓存服务,包括 Redis Client 、 Cache Client 等,用于缓存热点数据,减少数据库查询次数,提升接口响应速度。

存储服务,包括 Ceph Client 等,用于处理文件存储、大数据存储等需求。

消息队列,包括 QMQ Producer 、 QMQ Consumer 、 Kafka Producer 、 Kafka Consumer 等,用于处理异步任务、解耦服务,提升系统的并发处理能力和稳定性。

公共服务,包括 Qconfig Client 、 ABTest 等,用于获取系统配置、实现灰度发布、 A/B 测试等功能。

Node.js 开发与部署

项目开发流程

企业级 Node.js 项目开发遵循标准化的流程,从需求梳理到上线运维,每个环节都有明确的规范,确保项目质量和开发效率,具体流程如下:

需求梳理与文档管理,梳理项目需求,明确开发范围和功能点,编写需求文档、设计文档,确定技术方案和项目架构,形成需求清单( backlog )。

计划与开拨,制定开发计划,划分开发阶段和任务,分配开发人员和时间节点,搭建项目基础架构,初始化项目环境。

编码开发,按照项目架构和编码规范,进行代码编写,实现各个功能模块,注重代码的可读性、可维护性和可重用性,及时提交代码到版本管理工具(如 Git )。

构建与单元测试,使用构建工具对代码进行打包构建,编写单元测试用例,执行单元测试,确保每个功能模块能够正常运行,修复测试中发现的 bug 。

集成测试与发布测试,将各个模块集成在一起,进行集成测试,验证模块之间的交互是否正常;部署到测试环境,进行发布测试,模拟生产环境的场景,验证项目的整体功能和性能。

发布上线,测试通过后,进行上线部署,企业级部署通常采用堡垒机发布、灰度发布、正式发布的流程,逐步将应用推向生产环境,降低上线风险。

运维监控,上线后,对应用进行实时监控,处理线上 bug 和异常,优化应用性能,确保应用稳定运行。

项目实践( Express 框架)

Express 是 Node.js 最流行的 Web 框架,基于 http 模块封装,简化了 HTTP 服务器的开发流程,提供了路由、中间件、模板引擎等核心功能,以下是一个完整的 Express 项目实践,实现基础的 API 接口、健康检查、错误处理等功能,可直接运行。

项目初始化与依赖安装,打开命令行终端,执行以下命令,初始化项目并安装所需依赖:

1
2
3
4
5
6
# 初始化项目,生成package.json文件
npm init -y
# 安装express框架(核心依赖)
npm install express
# 安装nodemon(开发环境依赖,用于热更新,修改代码后自动重启服务器)
npm install nodemon --save-dev

修改 package.json ,添加启动脚本,方便项目运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"name": "node-express-demo",
"version": "1.0.0",
"main": "app.js",
"scripts": {
"start": "node app.js", // 生产环境启动命令
"dev": "nodemon app.js" // 开发环境启动命令(热更新)
},
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"nodemon": "^3.0.1"
}
}

编写核心代码( app.js ),实现基础路由、健康检查、错误处理等功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// 引入express框架
const express = require('express');
// 创建express应用实例
const app = express();
// 定义端口
const port = 3000;

// 中间件:解析JSON格式的请求体(用于处理POST请求的JSON数据)
app.use(express.json());

// 1. 基础路由:GET请求,返回欢迎信息
app.get('/', (req, res) => {
res.send({
status: 'success',
message: '欢迎使用Express应用'
});
});

// 2. 健康检查路由:用于监控应用运行状态
app.get('/health', (req, res) => {
res.send({
status: 'success',
message: '应用运行正常',
time: new Date().toString()
});
});

// 3. API路由示例:用户列表相关接口(GET获取列表,POST创建用户)
// 模拟用户数据
let users = [
{ id: 1, name: '张三', email: 'zhangsan@example.com' },
{ id: 2, name: '李四', email: 'lisi@example.com' }
];

// 获取用户列表
app.get('/api/users', (req, res) => {
res.send({
status: 'success',
data: users
});
});

// 创建新用户(POST请求,接收JSON格式参数)
app.post('/api/users', (req, res) => {
// 获取请求体中的参数
const { name, email } = req.body;
// 验证参数(简单校验)
if (!name || !email) {
return res.status(400).send({
status: 'fail',
message: '姓名和邮箱不能为空'
});
}
// 创建新用户
const newUser = {
id: users.length + 1,
name,
email
};
// 添加到用户列表
users.push(newUser);
// 返回创建后的用户信息
res.status(201).send({
status: 'success',
data: newUser
});
});

// 4. 404错误处理:当请求的路由不存在时触发
app.use((req, res) => {
res.status(404).send({
status: 'fail',
message: '请求的路由不存在'
});
});

// 5. 全局错误处理中间件:处理项目中所有的异常
app.use((err, req, res, next) => {
console.error('全局错误:', err.message);
res.status(500).send({
status: 'error',
message: '服务器内部错误,请稍后重试'
});
});

// 启动服务器,监听指定端口
app.listen(port, () => {
console.log(`Express应用运行在 http://localhost:${port}`);
});

项目运行与测试,执行以下命令启动项目,进行接口测试:

1
2
3
4
# 开发环境启动(热更新)
npm run dev
# 生产环境启动
npm start

启动成功后,可通过以下方式测试接口:

  1. 浏览器访问http://localhost:3000,查看欢迎信息;
  2. 访问http://localhost:3000/health,查看健康检查结果;
  3. 使用 Postman 发起 GET 请求http://localhost:3000/api/users,获取用户列表;
  4. 使用 Postman 发起 POST 请求http://localhost:3000/api/users,传递JSON格式参数({ “name”: “王五”, “email”: “wangwu@example.com“ }),创建新用户;
  5. 访问不存在的路由(如http://localhost:3000/api/test),测试404错误处理。

企业级部署模型

企业级 Node.js 项目的部署需考虑稳定性、可扩展性、可维护性,通常采用“Nginx + PM2 + Docker”的部署模型,三者协同工作,确保应用稳定运行,具体架构如下:

image-20260209185715325

Nginx 作为反向代理服务器,部署在最外层,主要负责:

  1. 接收客户端的所有请求,转发到后端的 Node.js 应用;
  2. 处理静态资源(如图片、 CSS 、 JS 文件),减少 Node.js 应用的压力;
  3. 实现负载均衡,当部署多个 Node.js 实例时,将请求均匀分配到各个实例,提升并发处理能力;
  4. 实现限流、降级机制,当 Node.js 应用出现异常时, Nginx 可直接返回错误响应,避免请求堆积,防止系统雪崩;
  5. 处理 HTTPS 加密、请求重定向、 gzip 压缩等操作,保证传输安全和传输效率。

PM2 作为 Node.js 应用的进程管理工具,用于管理 Node.js 应用的运行,主要负责:

  1. 守护进程,当 Node.js 应用崩溃时,自动重启应用,确保应用持续运行;
  2. 负载均衡,在单个服务器上启动多个 Node.js 实例,实现进程级别的负载均衡;
  3. 监控应用运行状态,输出 CPU 、内存、请求量等监控指标,便于排查问题;
  4. 日志管理,统一收集应用的日志,便于查看和分析。

Docker 作为容器化工具,用于封装 Node.js 应用及其依赖环境,主要负责:

  1. 提供一致的运行环境,解决“开发环境能运行,生产环境运行失败”的问题;
  2. 简化部署流程,将应用及其依赖打包为容器镜像,可快速在不同服务器上部署;
  3. 隔离应用环境,不同应用运行在不同容器中,互不干扰,提升系统稳定性;
  4. 提供预编译的扩展包,降低开发和维护成本。

部署流程简述,将 Node.js 应用打包为 Docker 镜像,通过 Docker 启动容器;使用 PM2 管理容器内的 Node.js 进程,启动多个实例;配置 Nginx ,将客户端请求转发到 PM2 管理的 Node.js 实例,实现负载均衡和反向代理;最后通过堡垒机进行发布,先灰度发布部分服务器,测试无问题后,再全量发布。

Node.js 运维监控

Node.js 应用上线后,运维监控是确保应用稳定运行的关键,主要包括调试排障、性能监控、压力测试等环节,及时发现并解决应用运行中的问题,优化应用性能。

调试工具与方法

Node.js 提供了多种调试工具和方法,用于排查开发和生产环境中的 bug ,常用方式如下:

V8 Inspector , Node.js 内置的调试工具,基于 Chrome DevTools ,支持断点调试、代码查看、变量监控等功能,使用方法如下:

  1. 启动应用时,添加–inspect 参数: node –inspect app.js ;
  2. 打开 Chrome 浏览器,访问 chrome://inspect ,即可看到正在运行的 Node.js 应用;
  3. 点击“inspect”,打开 Chrome DevTools ,即可进行断点调试,查看变量、调用栈等信息。

node-inspect , Node.js 内置的命令行调试工具,无需依赖浏览器,适合在服务器端调试,使用方法如下:

  1. 启动应用时,添加 inspect 参数: node inspect app.js ;
  2. 使用调试命令进行操作,常用命令:
  • c :继续执行到下一个断点;
  • n :执行下一行代码;
  • s :进入函数内部;
  • o :退出函数;
  • watch(变量名):监控指定变量的值;
  • repl :进入交互模式,查看变量的值。

日志调试,在应用中添加日志记录,输出关键信息(如请求参数、响应数据、错误信息等),通过日志排查问题。企业级实践中,会使用专业的日志工具(如 TripLog ),统一收集和管理日志,支持按级别、按时间查询日志,快速定位问题。

性能监控

性能监控主要关注应用的 CPU 使用率、内存占用、事件循环延迟、请求响应时间等指标,及时发现性能瓶颈,优化应用性能。

内存性能监控, Node.js 应用的内存泄漏是常见的性能问题,可通过以下方式监控和分析:

  1. 使用 process 模块,实时获取内存使用情况:
1
2
3
4
5
6
7
8
9
// 每隔1000ms,输出一次内存使用情况
setInterval(() => {
const memoryUsage = process.memoryUsage();
// 转换为MB,便于查看
const rss = (memoryUsage.rss / 1024 / 1024).toFixed(2) + 'MB'; // 常驻内存
const heapTotal = (memoryUsage.heapTotal / 1024 / 1024).toFixed(2) + 'MB'; // 堆总内存
const heapUsed = (memoryUsage.heapUsed / 1024 / 1024).toFixed(2) + 'MB'; // 已使用堆内存
console.log(`内存使用:RSS=${rss},HeapTotal=${heapTotal},HeapUsed=${heapUsed}`);
}, 1000);
  1. 使用 Chrome DevTools 的 Heap Snapshots 功能,拍摄内存快照,分析内存泄漏的原因,定位内存占用过高的对象和代码。

CPU 性能监控, CPU 使用率过高会导致应用响应缓慢,可通过以下方式监控和分析:

  1. 使用 process 模块,获取 CPU 使用率:
1
2
3
// 获取CPU使用情况
const cpuUsage = process.cpuUsage();
console.log('CPU使用情况:', cpuUsage);
  1. 使用 Chrome DevTools 的 CPU Profile 功能,录制 CPU 执行情况,分析哪些代码占用 CPU 过高,优化代码逻辑(如避免死循环、优化耗时操作)。

事件循环监控,事件循环延迟会导致异步操作响应缓慢,可通过以下方式监控:

  1. 使用 setImmediate 和 Date 对象,计算事件循环延迟:
1
2
3
4
5
6
7
8
9
10
11
setInterval(() => {
const start = Date.now();
setImmediate(() => {
const delay = Date.now() - start;
console.log(`事件循环延迟:${delay}ms`);
// 若延迟超过100ms,说明存在性能问题
if (delay > 100) {
console.warn('事件循环延迟过高,可能存在性能瓶颈');
}
});
}, 1000);

请求性能监控,监控 API 接口的响应时间,排查响应缓慢的接口,优化接口性能。可通过中间件记录每个请求的响应时间,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 记录请求响应时间的中间件
app.use((req, res, next) => {
const start = Date.now();
// 监听响应结束事件
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`请求 ${req.method} ${req.path} 响应时间:${duration}ms`);
// 若响应时间超过500ms,记录警告日志
if (duration > 500) {
console.warn(`警告:请求 ${req.method} ${req.path} 响应时间过长:${duration}ms`);
}
});
next();
});

压力测试

压力测试用于模拟高并发场景,测试应用的抗压能力和性能极限,找出应用在高并发下的性能瓶颈,常用的压力测试工具如下:

Apache Bench ( ab ), Apache 官方提供的压力测试工具,简单易用,适合快速测试接口的并发能力和响应时间,使用方法如下:

1
2
3
4
# 安装ab工具(Windows需安装Apache,Mac、Linux默认自带)
# 测试命令:ab -n 1000 -c 100 http://localhost:3000/api/users
# 说明:-n 总请求数,-c 并发请求数,后面跟测试的接口地址
ab -n 1000 -c 100 http://localhost:3000/api/users

执行命令后, ab 工具会输出测试结果,包括请求总数、并发数、响应时间(平均值、最小值、最大值)、吞吐量等指标,根据指标分析应用的抗压能力。

Webbench ,轻量级的压力测试工具,支持高并发测试,能够快速测试应用的最大吞吐量和抗压能力,使用方法与 ab 类似,适合简单的压力测试场景。

拓展与学习资源

Node.js 的学习是一个持续深入的过程,除了基础知识点和实践,还可以通过以下方式提升自身能力:

阅读 Node.js 源码,访问Node.js 官方 GitHub 仓库,阅读源码,深入理解Node.js的底层实现原理(如事件循环、异步I/O、模块加载机制等)。

参与代码贡献,向 Node.js 官方或第三方开源模块提交 PR ,修复 bug 、添加新功能,提升自身的代码能力和开源协作能力。

发布 NPM 包,将自己开发的工具函数、组件、框架发布到 npm 仓库,供其他开发者使用,积累项目经验。

加入 Node.js 社区,关注 Node.js 官方文档、技术博客、社区论坛,与其他开发者交流学习,了解 Node.js 的最新特性和技术趋势。

常用学习资源:

Node.js 官方文档 Express 官方文档 MongoDB 与 Node.js 结合使用 前端工程化工具手册

学习总结

Node.js 作为基于 V8 引擎的 JavaScript 运行环境,打破了 JavaScript 仅能在浏览器端运行的局限,成为前端工程化、服务端开发、跨端应用开发的核心技术。本文从 Node.js 的基础概念、核心特性、常用模块、开发部署到运维监控,全面梳理了 Node.js 的核心知识点,补充了完整可运行的实践代码,涵盖了从入门到企业级实践的全流程。

入门 Node.js ,首先需要掌握安装与 npm 的使用,理解 Node.js 的核心特性(单线程、异步非阻塞 I/O 、事件驱动、模块化),熟练运用常用核心模块( fs 、 http 、 path 、 events 等)实现基础功能。进阶阶段,可学习 Express 等 Web 框架,掌握 API 接口开发、中间件使用、错误处理等技巧,理解企业级项目的开发流程和部署模型( Nginx + PM2 + Docker )。高阶阶段,可深入学习 Node.js 的底层原理,参与开源项目,发布 NPM 包,提升自身的技术深度和广度。

Node.js 的核心优势在于处理高并发、 I/O 密集型任务,尤其适合前端工程化和服务端 API 开发,掌握 Node.js 不仅能提升前端开发效率,还能拓展自身的技术边界,成为全栈开发者。这份笔记可作为日常开发查阅、知识复习的核心参考,助力快速掌握 Node.js ,高效完成项目开发与落地。