Node.js完全指南:从入门到精通

一、Node.js基础概念

1.1 什么是Node.js?

Node.js是一个基于Chrome V8引擎的JavaScript运行环境,让JavaScript可以在服务器端运行。它使用事件驱动、非阻塞I/O模型,使其轻量且高效。

1.2 Node.js的历史

  • 2009年:Ryan Dahl创建了Node.js
  • 2010年:NPM(Node Package Manager)诞生
  • 2011年:npm 1.0发布
  • 2015年:Node.js基金会成立
  • 2016年:引入长期支持(LTS)版本
  • 至今:持续快速发展,广泛应用于后端开发

1.3 Node.js的特点

  • 单线程:使用单线程事件循环,避免线程切换开销
  • 异步非阻塞I/O:提高并发处理能力
  • 跨平台:可在Windows、Linux、Mac上运行
  • NPM生态:拥有世界上最庞大的开源库生态系统
  • JavaScript全栈:前后端统一语言,降低开发成本

1.4 Node.js的应用场景

  • Web应用:RESTful API、GraphQL服务
  • 实时应用:聊天应用、实时协作工具
  • 微服务:构建分布式系统
  • CLI工具:命令行工具开发
  • 数据流:处理大量数据
  • 物联网:IoT设备数据处理

二、Node.js安装和环境配置

2.1 安装Node.js

Windows系统
  1. 访问Node.js官网:https://nodejs.org/
  2. 下载LTS版本(推荐)或Current版本
  3. 运行安装程序,按提示完成安装
  4. 验证安装:
bash 复制代码
node --version
npm --version
Linux系统
bash 复制代码
# 使用包管理器安装
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install nodejs npm

# CentOS/RHEL
sudo yum install nodejs npm

# 使用NVM安装(推荐)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
source ~/.bashrc
nvm install --lts
nvm use --lts
Mac系统
bash 复制代码
# 使用Homebrew安装
brew install node

# 使用NVM安装
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
source ~/.bashrc
nvm install --lts

2.2 版本管理

使用NVM(Node Version Manager)
bash 复制代码
# 安装NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

# 查看可用版本
nvm list-remote

# 安装特定版本
nvm install 16.14.0

# 使用特定版本
nvm use 16.14.0

# 设置默认版本
nvm alias default 16.14.0

# 查看已安装版本
nvm list

# 卸载版本
nvm uninstall 16.14.0
使用n(简单版本管理器)
bash 复制代码
# 安装n
npm install -g n

# 安装最新LTS版本
n lts

# 安装最新版本
n latest

# 安装特定版本
n 16.14.0

# 切换版本
n

# 查看已安装版本
n ls

2.3 环境变量配置

bash 复制代码
# Windows系统
# 系统环境变量中添加:
# NODE_PATH = C:\Users\YourName\AppData\Roaming\npm\node_modules
# PATH = %NODE_PATH%;C:\Program Files\nodejs

# Linux/Mac系统
# 在 ~/.bashrc 或 ~/.zshrc 中添加:
export NODE_PATH=/usr/local/lib/node_modules
export PATH=$PATH:/usr/local/bin

# 重新加载配置
source ~/.bashrc

2.4 创建第一个Node.js应用

javascript 复制代码
// hello.js
console.log('Hello, Node.js!');

// 运行
node hello.js
javascript 复制代码
// http-server.js
const http = require('http');

const server = http.createServer((req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello, Node.js!');
});

server.listen(3000, () => {
    console.log('Server running at http://localhost:3000/');
});

// 运行
node http-server.js

三、模块系统

3.1 CommonJS模块系统

导出模块
javascript 复制代码
// math.js
// 方式1:导出单个值
module.exports = {
    add: function(a, b) {
        return a + b;
    },
    subtract: function(a, b) {
        return a - b;
    }
};

// 方式2:导出多个值
exports.add = function(a, b) {
    return a + b;
};

exports.subtract = function(a, b) {
    return a - b;
};

// 方式3:导出类
class Calculator {
    add(a, b) {
        return a + b;
    }
}

module.exports = Calculator;
导入模块
javascript 复制代码
// app.js
// 方式1:导入整个模块
const math = require('./math');
console.log(math.add(1, 2)); // 3

// 方式2:解构导入
const { add, subtract } = require('./math');
console.log(add(1, 2)); // 3

// 方式3:导入类
const Calculator = require('./math');
const calc = new Calculator();
console.log(calc.add(1, 2)); // 3

3.2 ES6模块系统

启用ES6模块
json 复制代码
// package.json
{
  "type": "module"
}
导出模块
javascript 复制代码
// math.mjs
// 方式1:命名导出
export function add(a, b) {
    return a + b;
}

export function subtract(a, b) {
    return a - b;
}

// 方式2:默认导出
export default class Calculator {
    add(a, b) {
        return a + b;
    }
}

// 方式3:混合导出
export const PI = 3.14159;
export function multiply(a, b) {
    return a * b;
}
导入模块
javascript 复制代码
// app.mjs
// 方式1:导入命名导出
import { add, subtract } from './math.mjs';
console.log(add(1, 2)); // 3

// 方式2:导入默认导出
import Calculator from './math.mjs';
const calc = new Calculator();
console.log(calc.add(1, 2)); // 3

// 方式3:导入所有
import * as math from './math.mjs';
console.log(math.add(1, 2)); // 3

// 方式4:动态导入
const module = await import('./math.mjs');
console.log(module.add(1, 2)); // 3

3.3 核心模块

1. fs(文件系统)
javascript 复制代码
const fs = require('fs');
const path = require('path');

// 同步读取文件
try {
    const data = fs.readFileSync('input.txt', 'utf8');
    console.log(data);
} catch (error) {
    console.error('读取文件失败:', error);
}

// 异步读取文件(推荐)
fs.readFile('input.txt', 'utf8', (error, data) => {
    if (error) {
        console.error('读取文件失败:', error);
        return;
    }
    console.log(data);
});

// 使用Promise
const fsPromises = require('fs').promises;

async function readFileAsync() {
    try {
        const data = await fsPromises.readFile('input.txt', 'utf8');
        console.log(data);
    } catch (error) {
        console.error('读取文件失败:', error);
    }
}

// 写入文件
fs.writeFile('output.txt', 'Hello, Node.js!', 'utf8', (error) => {
    if (error) {
        console.error('写入文件失败:', error);
        return;
    }
    console.log('文件写入成功');
});

// 追加内容
fs.appendFile('output.txt', '\n追加的内容', 'utf8', (error) => {
    if (error) {
        console.error('追加内容失败:', error);
        return;
    }
    console.log('内容追加成功');
});

// 删除文件
fs.unlink('output.txt', (error) => {
    if (error) {
        console.error('删除文件失败:', error);
        return;
    }
    console.log('文件删除成功');
});

// 创建目录
fs.mkdir('newdir', { recursive: true }, (error) => {
    if (error) {
        console.error('创建目录失败:', error);
        return;
    }
    console.log('目录创建成功');
});

// 读取目录
fs.readdir('.', (error, files) => {
    if (error) {
        console.error('读取目录失败:', error);
        return;
    }
    console.log('目录内容:', files);
});

// 检查文件是否存在
fs.access('input.txt', fs.constants.F_OK, (error) => {
    if (error) {
        console.log('文件不存在');
    } else {
        console.log('文件存在');
    }
});

// 获取文件信息
fs.stat('input.txt', (error, stats) => {
    if (error) {
        console.error('获取文件信息失败:', error);
        return;
    }
    console.log('文件信息:', stats);
    console.log('是否为文件:', stats.isFile());
    console.log('是否为目录:', stats.isDirectory());
    console.log('文件大小:', stats.size);
});

// 路径操作
const filePath = path.join(__dirname, 'files', 'input.txt');
console.log('文件路径:', filePath);
console.log('文件名:', path.basename(filePath));
console.log('目录名:', path.dirname(filePath));
console.log('扩展名:', path.extname(filePath));
console.log('绝对路径:', path.resolve(filePath));
2. http(HTTP服务器)
javascript 复制代码
const http = require('http');
const url = require('url');
const querystring = require('querystring');

// 创建简单的HTTP服务器
const server = http.createServer((req, res) => {
    // 处理CORS
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

    // 处理OPTIONS请求
    if (req.method === 'OPTIONS') {
        res.writeHead(200);
        res.end();
        return;
    }

    // 解析URL
    const parsedUrl = url.parse(req.url, true);
    const pathname = parsedUrl.pathname;
    const query = parsedUrl.query;

    console.log(`收到请求: ${req.method} ${pathname}`);

    // 路由处理
    if (pathname === '/') {
        res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
        res.end(`
            <!DOCTYPE html>
            <html>
            <head>
                <title>Node.js HTTP服务器</title>
            </head>
            <body>
                <h1>欢迎使用Node.js HTTP服务器</h1>
                <p>当前路径: ${pathname}</p>
            </body>
            </html>
        `);
    } else if (pathname === '/api/data') {
        // JSON响应
        const data = {
            message: '成功',
            data: [1, 2, 3, 4, 5]
        };
        res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
        res.end(JSON.stringify(data));
    } else {
        // 404页面
        res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
        res.end(`
            <!DOCTYPE html>
            <html>
            <head>
                <title>404 Not Found</title>
            </head>
            <body>
                <h1>404 - 页面不存在</h1>
                <p>您访问的页面不存在: ${pathname}</p>
            </body>
            </html>
        `);
    }
});

server.listen(3000, () => {
    console.log('服务器运行在 http://localhost:3000/');
});

// 处理POST请求
const server2 = http.createServer((req, res) => {
    if (req.method === 'POST' && req.url === '/api/login') {
        let body = '';
        
        req.on('data', chunk => {
            body += chunk.toString();
        });
        
        req.on('end', () => {
            try {
                const data = JSON.parse(body);
                console.log('接收到的数据:', data);
                
                res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
                res.end(JSON.stringify({
                    success: true,
                    message: '登录成功',
                    user: data
                }));
            } catch (error) {
                res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
                res.end(JSON.stringify({
                    success: false,
                    message: '数据格式错误'
                }));
            }
        });
    } else {
        res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
        res.end('404 Not Found');
    }
});

server2.listen(3001, () => {
    console.log('POST服务器运行在 http://localhost:3001/');
});
3. path(路径处理)
javascript 复制代码
const path = require('path');

// 路径拼接
const fullPath = path.join(__dirname, 'files', 'data.txt');
console.log('完整路径:', fullPath);

// 路径解析
const parsed = path.parse('/path/to/file.txt');
console.log('路径解析:', parsed);
// {
//   root: '/',
//   dir: '/path/to',
//   base: 'file.txt',
//   ext: '.txt',
//   name: 'file'
// }

// 获取文件名
console.log('文件名:', path.basename('/path/to/file.txt')); // file.txt
console.log('不含扩展名的文件名:', path.basename('/path/to/file.txt', '.txt')); // file

// 获取目录名
console.log('目录名:', path.dirname('/path/to/file.txt')); // /path/to

// 获取扩展名
console.log('扩展名:', path.extname('/path/to/file.txt')); // .txt

// 获取绝对路径
console.log('绝对路径:', path.resolve('files/data.txt'));

// 规范化路径
console.log('规范化路径:', path.normalize('/path/to/../to/./file.txt')); // /path/to/file.txt

// 判断是否为绝对路径
console.log('是否为绝对路径:', path.isAbsolute('/path/to/file.txt')); // true
console.log('是否为绝对路径:', path.isAbsolute('files/data.txt')); // false

// 获取当前工作目录
console.log('当前工作目录:', process.cwd());
console.log('__dirname:', __dirname);
console.log('__filename:', __filename);
4. events(事件处理)
javascript 复制代码
const EventEmitter = require('events');

// 创建事件发射器
class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();

// 监听事件
myEmitter.on('event', () => {
    console.log('事件触发!');
});

// 触发事件
myEmitter.emit('event');

// 带参数的事件
myEmitter.on('data', (data) => {
    console.log('收到数据:', data);
});

myEmitter.emit('data', { name: '张三', age: 25 });

// 只触发一次的事件
myEmitter.once('once', () => {
    console.log('这个事件只会触发一次');
});

myEmitter.emit('once');
myEmitter.emit('once'); // 不会触发

// 错误处理
myEmitter.on('error', (error) => {
    console.error('发生错误:', error.message);
});

myEmitter.emit('error', new Error('这是一个错误'));

// 移除事件监听器
const handler = () => {
    console.log('这个监听器会被移除');
};

myEmitter.on('remove', handler);
myEmitter.emit('remove');
myEmitter.removeListener('remove', handler);
myEmitter.emit('remove'); // 不会触发

// 获取监听器数量
console.log('监听器数量:', myEmitter.listenerCount('event'));

// 获取所有监听器
console.log('所有监听器:', myEmitter.listeners('event'));
5. stream(流处理)
javascript 复制代码
const fs = require('fs');
const { Transform } = require('stream');

// 读取流
const readStream = fs.createReadStream('input.txt', 'utf8');

readStream.on('data', (chunk) => {
    console.log('读取数据块:', chunk);
});

readStream.on('end', () => {
    console.log('读取完成');
});

readStream.on('error', (error) => {
    console.error('读取错误:', error);
});

// 写入流
const writeStream = fs.createWriteStream('output.txt', 'utf8');

writeStream.write('Hello, ');
writeStream.write('Node.js!\n');
writeStream.end('结束写入');

writeStream.on('finish', () => {
    console.log('写入完成');
});

writeStream.on('error', (error) => {
    console.error('写入错误:', error);
});

// 管道流(复制文件)
const readStream2 = fs.createReadStream('input.txt');
const writeStream2 = fs.createWriteStream('output.txt');

readStream2.pipe(writeStream2);

readStream2.on('end', () => {
    console.log('文件复制完成');
});

// 转换流(大写转换)
const upperCaseTransform = new Transform({
    transform(chunk, encoding, callback) {
        this.push(chunk.toString().toUpperCase());
        callback();
    }
});

fs.createReadStream('input.txt')
    .pipe(upperCaseTransform)
    .pipe(fs.createWriteStream('uppercase.txt'));

// 压缩流
const zlib = require('zlib');
const gzip = zlib.createGzip();

fs.createReadStream('input.txt')
    .pipe(gzip)
    .pipe(fs.createWriteStream('input.txt.gz'));

// 解压流
const gunzip = zlib.createGunzip();
fs.createReadStream('input.txt.gz')
    .pipe(gunzip)
    .pipe(fs.createWriteStream('uncompressed.txt'));
6. crypto(加密)
javascript 复制代码
const crypto = require('crypto');

// MD5哈希
const hash1 = crypto.createHash('md5').update('Hello, Node.js!').digest('hex');
console.log('MD5:', hash1);

// SHA256哈希
const hash2 = crypto.createHash('sha256').update('Hello, Node.js!').digest('hex');
console.log('SHA256:', hash2);

// HMAC
const hmac = crypto.createHmac('sha256', 'secret-key');
hmac.update('Hello, Node.js!');
console.log('HMAC:', hmac.digest('hex'));

// AES加密
const algorithm = 'aes-256-cbc';
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);

function encrypt(text) {
    const cipher = crypto.createCipheriv(algorithm, key, iv);
    let encrypted = cipher.update(text, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    return encrypted;
}

function decrypt(encrypted) {
    const decipher = crypto.createDecipheriv(algorithm, key, iv);
    let decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    return decrypted;
}

const original = 'Hello, Node.js!';
const encrypted = encrypt(original);
const decrypted = decrypt(encrypted);

console.log('原文:', original);
console.log('加密:', encrypted);
console.log('解密:', decrypted);

// 生成随机数
const randomBytes = crypto.randomBytes(16).toString('hex');
console.log('随机数:', randomBytes);

// 生成UUID
function generateUUID() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        const r = Math.random() * 16 | 0;
        const v = c === 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

console.log('UUID:', generateUUID());

四、NPM包管理

4.1 NPM基础命令

bash 复制代码
# 初始化项目
npm init

# 初始化项目(使用默认配置)
npm init -y

# 安装依赖
npm install

# 安装指定包
npm install package-name

# 安装到生产环境
npm install package-name --save

# 安装到开发环境
npm install package-name --save-dev

# 全局安装
npm install -g package-name

# 卸载包
npm uninstall package-name

# 更新包
npm update package-name

# 查看已安装的包
npm list

# 查看全局安装的包
npm list -g

# 查看包信息
npm info package-name

# 搜索包
npm search package-name

# 查看过期的包
npm outdated

# 清理缓存
npm cache clean --force

4.2 package.json详解

json 复制代码
{
  "name": "my-nodejs-app",
  "version": "1.0.0",
  "description": "我的Node.js应用",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "jest",
    "build": "webpack --mode production"
  },
  "dependencies": {
    "express": "^4.18.2",
    "mongoose": "^7.0.3",
    "dotenv": "^16.0.3"
  },
  "devDependencies": {
    "nodemon": "^2.0.22",
    "jest": "^29.5.0",
    "webpack": "^5.82.1"
  },
  "engines": {
    "node": ">=16.0.0",
    "npm": ">=8.0.0"
  },
  "author": "张三",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/username/repo.git"
  },
  "keywords": ["nodejs", "express", "api"]
}

4.3 常用NPM包

express - Web框架
bash 复制代码
npm install express
javascript 复制代码
const express = require('express');
const app = express();

// 中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 路由
app.get('/', (req, res) => {
    res.send('Hello, Express!');
});

app.get('/api/users', (req, res) => {
    res.json([
        { id: 1, name: '张三' },
        { id: 2, name: '李四' }
    ]);
});

app.post('/api/users', (req, res) => {
    const user = req.body;
    user.id = Date.now();
    res.status(201).json(user);
});

app.listen(3000, () => {
    console.log('Express服务器运行在 http://localhost:3000');
});
nodemon - 自动重启
bash 复制代码
npm install -D nodemon
json 复制代码
{
  "scripts": {
    "dev": "nodemon index.js"
  }
}
dotenv - 环境变量
bash 复制代码
npm install dotenv
javascript 复制代码
// .env
PORT=3000
DB_HOST=localhost
DB_USER=root
DB_PASS=password

// index.js
require('dotenv').config();

const port = process.env.PORT || 3000;
console.log('服务器端口:', port);
axios - HTTP客户端
bash 复制代码
npm install axios
javascript 复制代码
const axios = require('axios');

// GET请求
async function getData() {
    try {
        const response = await axios.get('https://api.example.com/data');
        console.log(response.data);
    } catch (error) {
        console.error('请求失败:', error);
    }
}

// POST请求
async function postData() {
    try {
        const response = await axios.post('https://api.example.com/users', {
            name: '张三',
            age: 25
        });
        console.log(response.data);
    } catch (error) {
        console.error('请求失败:', error);
    }
}
mongoose - MongoDB ODM
bash 复制代码
npm install mongoose
javascript 复制代码
const mongoose = require('mongoose');

// 连接数据库
mongoose.connect('mongodb://localhost:27017/mydatabase', {
    useNewUrlParser: true,
    useUnifiedTopology: true
});

// 定义模型
const UserSchema = new mongoose.Schema({
    name: { type: String, required: true },
    age: { type: Number, required: true },
    email: { type: String, required: true, unique: true }
});

const User = mongoose.model('User', UserSchema);

// 创建用户
async function createUser() {
    const user = new User({
        name: '张三',
        age: 25,
        email: 'zhangsan@example.com'
    });
    await user.save();
    console.log('用户创建成功:', user);
}

// 查询用户
async function findUsers() {
    const users = await User.find({ age: { $gte: 20 } });
    console.log('查询结果:', users);
}

// 更新用户
async function updateUser(id) {
    const user = await User.findByIdAndUpdate(
        id,
        { age: 26 },
        { new: true }
    );
    console.log('用户更新成功:', user);
}

// 删除用户
async function deleteUser(id) {
    await User.findByIdAndDelete(id);
    console.log('用户删除成功');
}

五、Express框架详解

5.1 Express基础

javascript 复制代码
const express = require('express');
const app = express();

// 中间件配置
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));

// 路由
app.get('/', (req, res) => {
    res.send('Hello, Express!');
});

app.get('/about', (req, res) => {
    res.send('关于我们');
});

// 路由参数
app.get('/users/:id', (req, res) => {
    const userId = req.params.id;
    res.send(`用户ID: ${userId}`);
});

// 查询参数
app.get('/search', (req, res) => {
    const keyword = req.query.keyword;
    res.send(`搜索关键词: ${keyword}`);
});

// POST请求
app.post('/users', (req, res) => {
    const user = req.body;
    res.status(201).json(user);
});

// 启动服务器
app.listen(3000, () => {
    console.log('服务器运行在 http://localhost:3000');
});

5.2 路由器

javascript 复制代码
const express = require('express');
const router = express.Router();

// 用户路由
router.get('/', (req, res) => {
    res.json([
        { id: 1, name: '张三' },
        { id: 2, name: '李四' }
    ]);
});

router.get('/:id', (req, res) => {
    const userId = req.params.id;
    res.json({ id: userId, name: '张三' });
});

router.post('/', (req, res) => {
    const user = req.body;
    user.id = Date.now();
    res.status(201).json(user);
});

router.put('/:id', (req, res) => {
    const userId = req.params.id;
    const user = req.body;
    res.json({ id: userId, ...user });
});

router.delete('/:id', (req, res) => {
    const userId = req.params.id;
    res.json({ message: `用户${userId}已删除` });
});

module.exports = router;

// 在主应用中使用
const userRoutes = require('./routes/users');
app.use('/api/users', userRoutes);

5.3 中间件

javascript 复制代码
// 日志中间件
const logger = (req, res, next) => {
    console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
    next();
};

// 认证中间件
const auth = (req, res, next) => {
    const token = req.headers.authorization;
    if (!token) {
        return res.status(401).json({ message: '未授权' });
    }
    // 验证token
    next();
};

// 错误处理中间件
const errorHandler = (err, req, res, next) => {
    console.error(err.stack);
    res.status(500).json({ message: '服务器错误' });
};

// 使用中间件
app.use(logger);
app.use('/api/protected', auth);

// 错误处理
app.use(errorHandler);

5.4 模板引擎

javascript 复制代码
// 安装EJS
npm install ejs

// 配置模板引擎
app.set('view engine', 'ejs');
app.set('views', './views');

// 渲染模板
app.get('/', (req, res) => {
    res.render('index', {
        title: '我的网站',
        users: [
            { name: '张三', age: 25 },
            { name: '李四', age: 30 }
        ]
    });
});

// views/index.ejs
<!DOCTYPE html>
<html>
<head>
    <title><%= title %></title>
</head>
<body>
    <h1><%= title %></h1>
    <ul>
        <% users.forEach(user => { %>
            <li><%= user.name %> - <%= user.age %>岁</li>
        <% }) %>
    </ul>
</body>
</html>

六、数据库操作

6.1 MongoDB

javascript 复制代码
const mongoose = require('mongoose');

// 连接数据库
mongoose.connect('mongodb://localhost:27017/myapp');

// 定义Schema
const userSchema = new mongoose.Schema({
    name: { type: String, required: true },
    email: { type: String, required: true, unique: true },
    age: { type: Number, default: 0 },
    createdAt: { type: Date, default: Date.now }
});

// 创建Model
const User = mongoose.model('User', userSchema);

// CRUD操作

// 创建
async function createUser() {
    const user = new User({
        name: '张三',
        email: 'zhangsan@example.com',
        age: 25
    });
    await user.save();
    return user;
}

// 读取
async function getUsers() {
    const users = await User.find({ age: { $gte: 18 } })
        .sort({ age: -1 })
        .limit(10);
    return users;
}

async function getUserById(id) {
    const user = await User.findById(id);
    return user;
}

// 更新
async function updateUser(id, updates) {
    const user = await User.findByIdAndUpdate(
        id,
        updates,
        { new: true, runValidators: true }
    );
    return user;
}

// 删除
async function deleteUser(id) {
    await User.findByIdAndDelete(id);
}

6.2 MySQL

javascript 复制代码
const mysql = require('mysql2/promise');

// 创建连接池
const pool = mysql.createPool({
    host: 'localhost',
    user: 'root',
    password: 'password',
    database: 'myapp',
    waitForConnections: true,
    connectionLimit: 10,
    queueLimit: 0
});

// CRUD操作

// 创建
async function createUser(user) {
    const sql = 'INSERT INTO users (name, email, age) VALUES (?, ?, ?)';
    const [result] = await pool.execute(sql, [user.name, user.email, user.age]);
    return result.insertId;
}

// 读取
async function getUsers() {
    const [rows] = await pool.execute('SELECT * FROM users WHERE age >= ?', [18]);
    return rows;
}

async function getUserById(id) {
    const [rows] = await pool.execute('SELECT * FROM users WHERE id = ?', [id]);
    return rows[0];
}

// 更新
async function updateUser(id, updates) {
    const sql = 'UPDATE users SET name = ?, email = ?, age = ? WHERE id = ?';
    const [result] = await pool.execute(sql, [updates.name, updates.email, updates.age, id]);
    return result.affectedRows > 0;
}

// 删除
async function deleteUser(id) {
    const sql = 'DELETE FROM users WHERE id = ?';
    const [result] = await pool.execute(sql, [id]);
    return result.affectedRows > 0;
}

// 事务
async function transferMoney(fromId, toId, amount) {
    const connection = await pool.getConnection();
    try {
        await connection.beginTransaction();

        // 扣款
        await connection.execute(
            'UPDATE users SET balance = balance - ? WHERE id = ?',
            [amount, fromId]
        );

        // 加款
        await connection.execute(
            'UPDATE users SET balance = balance + ? WHERE id = ?',
            [amount, toId]
        );

        await connection.commit();
        return true;
    } catch (error) {
        await connection.rollback();
        throw error;
    } finally {
        connection.release();
    }
}

七、实战项目:RESTful API

7.1 项目结构

复制代码
my-api/
├── config/
│   └── database.js
├── models/
│   └── User.js
├── routes/
│   └── users.js
├── middleware/
│   └── auth.js
├── controllers/
│   └── userController.js
├── app.js
├── .env
└── package.json

7.2 实现代码

javascript 复制代码
// package.json
{
  "name": "my-api",
  "version": "1.0.0",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js"
  },
  "dependencies": {
    "express": "^4.18.2",
    "mongoose": "^7.0.3",
    "dotenv": "^16.0.3",
    "bcryptjs": "^2.4.3",
    "jsonwebtoken": "^9.0.0"
  },
  "devDependencies": {
    "nodemon": "^2.0.22"
  }
}

// .env
PORT=3000
MONGODB_URI=mongodb://localhost:27017/myapi
JWT_SECRET=your-secret-key

// config/database.js
const mongoose = require('mongoose');

const connectDB = async () => {
    try {
        await mongoose.connect(process.env.MONGODB_URI);
        console.log('MongoDB连接成功');
    } catch (error) {
        console.error('MongoDB连接失败:', error);
        process.exit(1);
    }
};

module.exports = connectDB;

// models/User.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true,
        trim: true
    },
    email: {
        type: String,
        required: true,
        unique: true,
        trim: true,
        lowercase: true
    },
    password: {
        type: String,
        required: true,
        minlength: 6
    },
    role: {
        type: String,
        enum: ['user', 'admin'],
        default: 'user'
    }
}, {
    timestamps: true
});

// 密码加密
userSchema.pre('save', async function(next) {
    if (!this.isModified('password')) {
        return next();
    }
    const salt = await bcrypt.genSalt(10);
    this.password = await bcrypt.hash(this.password, salt);
    next();
});

// 密码验证
userSchema.methods.comparePassword = async function(candidatePassword) {
    return await bcrypt.compare(candidatePassword, this.password);
};

module.exports = mongoose.model('User', userSchema);

// controllers/userController.js
const User = require('../models/User');
const jwt = require('jsonwebtoken');

// 生成JWT
const generateToken = (userId) => {
    return jwt.sign({ userId }, process.env.JWT_SECRET, {
        expiresIn: '7d'
    });
};

// 注册
exports.register = async (req, res) => {
    try {
        const { name, email, password } = req.body;

        // 检查用户是否已存在
        const existingUser = await User.findOne({ email });
        if (existingUser) {
            return res.status(400).json({ message: '邮箱已被注册' });
        }

        // 创建用户
        const user = new User({ name, email, password });
        await user.save();

        // 生成token
        const token = generateToken(user._id);

        res.status(201).json({
            message: '注册成功',
            token,
            user: {
                id: user._id,
                name: user.name,
                email: user.email,
                role: user.role
            }
        });
    } catch (error) {
        res.status(500).json({ message: '服务器错误', error: error.message });
    }
};

// 登录
exports.login = async (req, res) => {
    try {
        const { email, password } = req.body;

        // 查找用户
        const user = await User.findOne({ email });
        if (!user) {
            return res.status(401).json({ message: '邮箱或密码错误' });
        }

        // 验证密码
        const isMatch = await user.comparePassword(password);
        if (!isMatch) {
            return res.status(401).json({ message: '邮箱或密码错误' });
        }

        // 生成token
        const token = generateToken(user._id);

        res.json({
            message: '登录成功',
            token,
            user: {
                id: user._id,
                name: user.name,
                email: user.email,
                role: user.role
            }
        });
    } catch (error) {
        res.status(500).json({ message: '服务器错误', error: error.message });
    }
};

// 获取用户信息
exports.getProfile = async (req, res) => {
    try {
        const user = await User.findById(req.userId).select('-password');
        if (!user) {
            return res.status(404).json({ message: '用户不存在' });
        }
        res.json(user);
    } catch (error) {
        res.status(500).json({ message: '服务器错误', error: error.message });
    }
};

// 更新用户信息
exports.updateProfile = async (req, res) => {
    try {
        const { name, email } = req.body;
        const user = await User.findByIdAndUpdate(
            req.userId,
            { name, email },
            { new: true, runValidators: true }
        ).select('-password');
        
        if (!user) {
            return res.status(404).json({ message: '用户不存在' });
        }
        
        res.json({ message: '更新成功', user });
    } catch (error) {
        res.status(500).json({ message: '服务器错误', error: error.message });
    }
};

// middleware/auth.js
const jwt = require('jsonwebtoken');

const auth = async (req, res, next) => {
    try {
        const token = req.header('Authorization')?.replace('Bearer ', '');
        
        if (!token) {
            return res.status(401).json({ message: '未提供认证token' });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        req.userId = decoded.userId;
        next();
    } catch (error) {
        res.status(401).json({ message: '无效的token' });
    }
};

module.exports = auth;

// routes/users.js
const express = require('express');
const router = express.Router();
const { register, login, getProfile, updateProfile } = require('../controllers/userController');
const auth = require('../middleware/auth');

router.post('/register', register);
router.post('/login', login);
router.get('/profile', auth, getProfile);
router.put('/profile', auth, updateProfile);

module.exports = router;

// app.js
require('dotenv').config();
const express = require('express');
const connectDB = require('./config/database');
const userRoutes = require('./routes/users');

const app = express();

// 连接数据库
connectDB();

// 中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 路由
app.use('/api/users', userRoutes);

// 错误处理
app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).json({ message: '服务器错误' });
});

// 启动服务器
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`服务器运行在 http://localhost:${PORT}`);
});

八、Node.js最佳实践

8.1 错误处理

javascript 复制代码
// 使用异步函数和try-catch
async function asyncOperation() {
    try {
        const result = await someAsyncOperation();
        return result;
    } catch (error) {
        console.error('操作失败:', error);
        throw error;
    }
}

// 错误处理中间件
app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).json({
        message: '服务器错误',
        error: process.env.NODE_ENV === 'development' ? err.message : {}
    });
});

// 未捕获的Promise拒绝
process.on('unhandledRejection', (reason, promise) => {
    console.error('未处理的Promise拒绝:', reason);
});

// 未捕获的异常
process.on('uncaughtException', (error) => {
    console.error('未捕获的异常:', error);
    process.exit(1);
});

8.2 安全性

javascript 复制代码
// 使用helmet
const helmet = require('helmet');
app.use(helmet());

// 使用cors
const cors = require('cors');
app.use(cors());

// 输入验证
const { body, validationResult } = require('express-validator');

app.post('/users', [
    body('name').notEmpty().withMessage('姓名不能为空'),
    body('email').isEmail().withMessage('邮箱格式不正确'),
    body('password').isLength({ min: 6 }).withMessage('密码至少6位')
], (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        return res.status(400).json({ errors: errors.array() });
    }
    // 处理请求
});

// 环境变量
require('dotenv').config();

// 限制请求频率
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15分钟
    max: 100 // 限制100次请求
});
app.use(limiter);

8.3 性能优化

javascript 复制代码
// 启用Gzip压缩
const compression = require('compression');
app.use(compression());

// 使用缓存
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 600 }); // 10分钟缓存

app.get('/api/data', async (req, res) => {
    const cacheKey = 'data';
    const cachedData = cache.get(cacheKey);
    
    if (cachedData) {
        return res.json(cachedData);
    }
    
    const data = await fetchData();
    cache.set(cacheKey, data);
    res.json(data);
});

// 使用连接池
const pool = mysql.createPool({
    connectionLimit: 10,
    // 其他配置
});

// 使用集群(多进程)
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    for (let i = 0; i < numCPUs; i++) {
        cluster.fork();
    }
} else {
    // 启动服务器
    app.listen(3000);
}

8.4 日志记录

javascript 复制代码
const winston = require('winston');

const logger = winston.createLogger({
    level: 'info',
    format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.json()
    ),
    transports: [
        new winston.transports.File({ filename: 'error.log', level: 'error' }),
        new winston.transports.File({ filename: 'combined.log' })
    ]
});

if (process.env.NODE_ENV !== 'production') {
    logger.add(new winston.transports.Console({
        format: winston.format.simple()
    }));
}

// 使用日志
logger.info('服务器启动');
logger.error('发生错误', error);

九、部署和运维

9.1 PM2进程管理

bash 复制代码
# 安装PM2
npm install -g pm2

# 启动应用
pm2 start app.js

# 启动应用并指定名称
pm2 start app.js --name my-app

# 列出所有进程
pm2 list

# 查看日志
pm2 logs

# 重启应用
pm2 restart my-app

# 停止应用
pm2 stop my-app

# 删除应用
pm2 delete my-app

# 监控
pm2 monit

# 保存进程列表
pm2 save

# 设置开机自启
pm2 startup

9.2 Docker容器化

dockerfile 复制代码
# Dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install --production

COPY . .

EXPOSE 3000

CMD ["node", "app.js"]
bash 复制代码
# 构建镜像
docker build -t my-nodejs-app .

# 运行容器
docker run -p 3000:3000 my-nodejs-app
yaml 复制代码
# docker-compose.yml
version: '3'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - MONGODB_URI=mongodb://mongo:27017/myapp
    depends_on:
      - mongo
  
  mongo:
    image: mongo:latest
    ports:
      - "27017:27017"
    volumes:
      - mongo-data:/data/db

volumes:
  mongo-data:
bash 复制代码
# 使用docker-compose启动
docker-compose up -d

十、总结

Node.js是一个功能强大、生态丰富的后端开发平台。通过本文的学习,你应该掌握了:

  1. Node.js的基础概念和安装配置
  2. 模块系统(CommonJS和ES6)
  3. 核心模块的使用(fs、http、path、events等)
  4. NPM包管理和常用包
  5. Express框架的详细使用
  6. 数据库操作(MongoDB、MySQL)
  7. 完整的RESTful API项目实战
  8. Node.js最佳实践(错误处理、安全性、性能优化)
  9. 部署和运维(PM2、Docker)

学习建议

  • 多动手实践,创建自己的项目
  • 深入理解Node.js的异步编程模型
  • 学习TypeScript提高代码质量
  • 关注Node.js的最新发展
  • 参与开源项目,学习优秀的代码
  • 掌握监控和调试技巧

Node.js的学习是一个持续的过程,随着技术的发展,Node.js也在不断进化。保持学习的热情,不断提升自己的技能,你一定能成为一名优秀的Node.js开发者!


希望这篇Node.js详解教程对你有所帮助!如果你有任何问题或建议,欢迎留言讨论。持续学习,不断进步,让我们一起在后端开发的道路上越走越远!

相关推荐
willow2 小时前
Nodejs使用
node.js
book123_0_993 小时前
node.js+npm的环境配置以及添加镜像(保姆级教程)
arcgis·npm·node.js
San30.3 小时前
手写 Mini Cursor:基于 Node.js 与 LangChain 的开发实战
人工智能·langchain·node.js·agent
好家伙VCC3 小时前
# Deno框架实战:从零搭建一个安全、高效的Node.js替代项目 在现代
java·python·安全·node.js
青春男大3 小时前
Node.js快速上手
node.js
猫头虎-前端技术3 小时前
这个项目需要Node 16,那个项目需要Node 18:如何解决多项目Node.js版本管理问题
前端·javascript·chrome·typescript·node.js·json·firefox
智能工业品检测-奇妙智能4 小时前
快速直播:Node.js + FFmpeg + flv.js 全栈实战
javascript·ffmpeg·node.js
minglie14 小时前
飞书聊天机器人事件回调测试
node.js·飞书
Less^_^4 小时前
Node.js 解构赋值快速入门
node.js