Node.js从入门到精通完整指南
目录
- Node.js基础
- 核心模块详解
- 文件系统操作
- HTTP服务器开发
- Express框架
- 数据库操作
- 异步编程
- 中间件开发
- 错误处理
- 性能优化
- 部署与监控
- 高级特性
1. Node.js基础
1.1 什么是Node.js
Node.js是基于Chrome V8引擎的JavaScript运行环境,让JavaScript能够在服务器端运行。
特点:
- 事件驱动、非阻塞I/O模型
- 单线程但高并发
- 跨平台
- 丰富的包生态系统(npm)
1.2 安装与环境配置
# 检查Node.js版本
node --version# 检查npm版本
npm --version# 创建新项目
mkdir my-node-app
cd my-node-app
npm init -y
1.3 第一个Node.js程序
// hello.js
console.log('Hello, Node.js!');
console.log('当前Node.js版本:', process.version);
console.log('当前工作目录:', process.cwd());
console.log('命令行参数:', process.argv);
# 运行程序
node hello.js
1.4 模块系统
CommonJS模块 (传统方式):
// math.js - 导出模块
function add(a, b) {return a + b;
}function subtract(a, b) {return a - b;
}// 导出方式1:逐个导出
exports.add = add;
exports.subtract = subtract;// 导出方式2:整体导出
module.exports = {add,subtract,multiply: (a, b) => a * b
};
// app.js - 导入模块
const math = require('./math');
// 或者使用解构赋值
const { add, subtract } = require('./math');console.log(math.add(5, 3)); // 8
console.log(subtract(5, 3)); // 2
ES6模块 (现代方式):
// math.mjs
export function add(a, b) {return a + b;
}export function subtract(a, b) {return a - b;
}// 默认导出
export default function multiply(a, b) {return a * b;
}
// app.mjs
import multiply, { add, subtract } from './math.mjs';console.log(add(5, 3)); // 8
console.log(multiply(5, 3)); // 15
2. 核心模块详解
2.1 path模块 - 路径处理
const path = require('path');// 路径拼接
const fullPath = path.join('/users', 'john', 'documents', 'file.txt');
console.log(fullPath); // /users/john/documents/file.txt// 路径解析
const filePath = '/home/user/documents/file.txt';
console.log('目录名:', path.dirname(filePath)); // /home/user/documents
console.log('文件名:', path.basename(filePath)); // file.txt
console.log('扩展名:', path.extname(filePath)); // .txt// 路径规范化
const messyPath = '/home/user/../user/./documents//file.txt';
console.log('规范化路径:', path.normalize(messyPath));
// /home/user/documents/file.txt
2.2 url模块 - URL处理
const url = require('url');const myUrl = 'https://www.example.com:8080/path/to/resource?name=john&age=30#section1';// 解析URL
const parsedUrl = url.parse(myUrl, true);
console.log(parsedUrl);
/*
{protocol: 'https:',host: 'www.example.com:8080',hostname: 'www.example.com',port: '8080',pathname: '/path/to/resource',query: { name: 'john', age: '30' },hash: '#section1'
}
*/// 构建URL
const newUrl = url.format({protocol: 'https:',hostname: 'api.example.com',port: 3000,pathname: '/users',query: { page: 1, limit: 10 }
});
console.log(newUrl); // https://api.example.com:3000/users?page=1&limit=10
2.3 querystring模块 - 查询字符串处理
const querystring = require('querystring');// 解析查询字符串
const query = 'name=john&age=30&skills=js&skills=node';
const parsed = querystring.parse(query);
console.log(parsed);
// { name: 'john', age: '30', skills: ['js', 'node'] }// 构建查询字符串
const obj = { name: 'jane', age: 25, city: 'New York' };
const queryStr = querystring.stringify(obj);
console.log(queryStr); // name=jane&age=25&city=New%20York
3. 文件系统操作
3.1 基本文件操作
const fs = require('fs');
const path = require('path');// 同步读取文件
try {const data = fs.readFileSync('example.txt', 'utf8');console.log('文件内容:', data);
} catch (error) {console.error('读取文件失败:', error.message);
}// 异步读取文件
fs.readFile('example.txt', 'utf8', (err, data) => {if (err) {console.error('读取文件失败:', err.message);return;}console.log('文件内容:', data);
});// Promise方式读取文件
const fsPromises = fs.promises;async function readFileAsync() {try {const data = await fsPromises.readFile('example.txt', 'utf8');console.log('文件内容:', data);} catch (error) {console.error('读取文件失败:', error.message);}
}
3.2 文件写入操作
const fs = require('fs');// 写入文件
const content = 'Hello, Node.js File System!';// 异步写入
fs.writeFile('output.txt', content, 'utf8', (err) => {if (err) {console.error('写入失败:', err.message);return;}console.log('文件写入成功!');
});// 追加内容
fs.appendFile('output.txt', '\n追加的内容', 'utf8', (err) => {if (err) {console.error('追加失败:', err.message);return;}console.log('内容追加成功!');
});
3.3 目录操作
const fs = require('fs');
const path = require('path');// 创建目录
fs.mkdir('new-directory', { recursive: true }, (err) => {if (err) {console.error('创建目录失败:', err.message);return;}console.log('目录创建成功!');
});// 读取目录
fs.readdir('.', (err, files) => {if (err) {console.error('读取目录失败:', err.message);return;}console.log('目录内容:');files.forEach(file => {const filePath = path.join('.', file);const stats = fs.statSync(filePath);if (stats.isDirectory()) {console.log(`📁 ${file}/`);} else {console.log(`📄 ${file} (${stats.size} bytes)`);}});
});
3.4 文件流操作
const fs = require('fs');
const path = require('path');// 创建可读流
const readStream = fs.createReadStream('large-file.txt', {encoding: 'utf8',highWaterMark: 1024 // 缓冲区大小
});// 创建可写流
const writeStream = fs.createWriteStream('output-stream.txt');// 流事件处理
readStream.on('data', (chunk) => {console.log(`读取到 ${chunk.length} 字节数据`);writeStream.write(chunk);
});readStream.on('end', () => {console.log('文件读取完成');writeStream.end();
});readStream.on('error', (err) => {console.error('读取错误:', err.message);
});// 使用管道简化流操作
const inputStream = fs.createReadStream('input.txt');
const outputStream = fs.createWriteStream('output-pipe.txt');inputStream.pipe(outputStream);
4. HTTP服务器开发
4.1 基本HTTP服务器
const http = require('http');
const url = require('url');
const querystring = require('querystring');// 创建HTTP服务器
const server = http.createServer((req, res) => {const parsedUrl = url.parse(req.url, true);const method = req.method;const pathname = parsedUrl.pathname;const query = parsedUrl.query;// 设置响应头res.setHeader('Content-Type', 'application/json; charset=utf-8');res.setHeader('Access-Control-Allow-Origin', '*');console.log(`${method} ${pathname}`);// 路由处理if (pathname === '/' && method === 'GET') {res.statusCode = 200;res.end(JSON.stringify({message: '欢迎使用Node.js HTTP服务器!',timestamp: new Date().toISOString()}));} else if (pathname === '/api/users' && method === 'GET') {const users = [{ id: 1, name: 'Alice', email: 'alice@example.com' },{ id: 2, name: 'Bob', email: 'bob@example.com' }];res.statusCode = 200;res.end(JSON.stringify({ users }));} else if (pathname === '/api/users' && method === 'POST') {let body = '';req.on('data', chunk => {body += chunk.toString();});req.on('end', () => {try {const userData = JSON.parse(body);// 这里应该保存到数据库res.statusCode = 201;res.end(JSON.stringify({message: '用户创建成功',user: { id: Date.now(), ...userData }}));} catch (error) {res.statusCode = 400;res.end(JSON.stringify({error: '无效的JSON数据'}));}});} else {res.statusCode = 404;res.end(JSON.stringify({error: '页面未找到'}));}
});// 启动服务器
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {console.log(`服务器运行在 http://localhost:${PORT}`);
});// 优雅关闭
process.on('SIGTERM', () => {console.log('收到SIGTERM信号,正在关闭服务器...');server.close(() => {console.log('服务器已关闭');process.exit(0);});
});
4.2 HTTPS服务器
const https = require('https');
const fs = require('fs');// SSL证书配置
const options = {key: fs.readFileSync('private-key.pem'),cert: fs.readFileSync('certificate.pem')
};const server = https.createServer(options, (req, res) => {res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });res.end(`<h1>HTTPS服务器</h1><p>这是一个安全的HTTPS连接</p><p>当前时间: ${new Date().toLocaleString()}</p>`);
});server.listen(443, () => {console.log('HTTPS服务器运行在 https://localhost:443');
});
5. Express框架
5.1 Express基础
// 首先安装Express: npm install expressconst express = require('express');
const app = express();// 中间件配置
app.use(express.json()); // 解析JSON请求体
app.use(express.urlencoded({ extended: true })); // 解析URL编码请求体
app.use(express.static('public')); // 静态文件服务// 基本路由
app.get('/', (req, res) => {res.json({message: '欢迎使用Express!',version: '1.0.0'});
});// 路由参数
app.get('/users/:id', (req, res) => {const userId = req.params.id;res.json({message: `获取用户信息`,userId: userId});
});// 查询参数
app.get('/search', (req, res) => {const { q, page = 1, limit = 10 } = req.query;res.json({query: q,page: parseInt(page),limit: parseInt(limit),results: []});
});// POST路由
app.post('/users', (req, res) => {const { name, email } = req.body;if (!name || !email) {return res.status(400).json({error: '姓名和邮箱不能为空'});}// 模拟保存到数据库const user = {id: Date.now(),name,email,createdAt: new Date()};res.status(201).json({message: '用户创建成功',user});
});const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {console.log(`Express服务器运行在端口 ${PORT}`);
});
5.2 Express路由模块化
// routes/users.js
const express = require('express');
const router = express.Router();// 用户数据模拟
let users = [{ id: 1, name: 'Alice', email: 'alice@example.com' },{ id: 2, name: 'Bob', email: 'bob@example.com' }
];// 获取所有用户
router.get('/', (req, res) => {res.json({ users });
});// 获取单个用户
router.get('/:id', (req, res) => {const user = users.find(u => u.id === parseInt(req.params.id));if (!user) {return res.status(404).json({ error: '用户不存在' });}res.json({ user });
});// 创建用户
router.post('/', (req, res) => {const { name, email } = req.body;const user = {id: Math.max(...users.map(u => u.id)) + 1,name,email};users.push(user);res.status(201).json({ user });
});// 更新用户
router.put('/:id', (req, res) => {const userId = parseInt(req.params.id);const userIndex = users.findIndex(u => u.id === userId);if (userIndex === -1) {return res.status(404).json({ error: '用户不存在' });}users[userIndex] = { ...users[userIndex], ...req.body };res.json({ user: users[userIndex] });
});// 删除用户
router.delete('/:id', (req, res) => {const userId = parseInt(req.params.id);const userIndex = users.findIndex(u => u.id === userId);if (userIndex === -1) {return res.status(404).json({ error: '用户不存在' });}const deletedUser = users.splice(userIndex, 1)[0];res.json({ message: '用户删除成功', user: deletedUser });
});module.exports = router;
// app.js - 使用路由模块
const express = require('express');
const usersRouter = require('./routes/users');const app = express();app.use(express.json());
app.use('/api/users', usersRouter);app.listen(3000, () => {console.log('服务器运行在端口 3000');
});
5.3 Express中间件
const express = require('express');
const app = express();// 日志中间件
const logger = (req, res, next) => {const timestamp = new Date().toISOString();console.log(`[${timestamp}] ${req.method} ${req.url}`);next(); // 传递控制权给下一个中间件
};// 认证中间件
const authenticate = (req, res, next) => {const token = req.headers.authorization;if (!token) {return res.status(401).json({ error: '缺少认证令牌' });}// 模拟令牌验证if (token !== 'Bearer valid-token') {return res.status(401).json({ error: '无效的令牌' });}req.user = { id: 1, name: 'Alice' }; // 设置用户信息next();
};// 错误处理中间件
const errorHandler = (err, req, res, next) => {console.error(err.stack);if (err.type === 'validation') {return res.status(400).json({ error: err.message });}res.status(500).json({ error: '服务器内部错误' });
};// 应用中间件
app.use(logger);
app.use(express.json());// 公开路由
app.get('/', (req, res) => {res.json({ message: '欢迎访问API' });
});// 需要认证的路由
app.get('/profile', authenticate, (req, res) => {res.json({message: '用户资料',user: req.user});
});// 触发错误的路由(用于测试错误处理)
app.get('/error', (req, res, next) => {const error = new Error('这是一个测试错误');error.type = 'validation';next(error);
});// 应用错误处理中间件(必须放在最后)
app.use(errorHandler);app.listen(3000, () => {console.log('服务器运行在端口 3000');
});
6. 数据库操作
6.1 MongoDB集成(使用Mongoose)
// 首先安装: npm install mongooseconst mongoose = require('mongoose');
const express = require('express');// 连接MongoDB
mongoose.connect('mongodb://localhost:27017/nodeapp', {useNewUrlParser: true,useUnifiedTopology: true
})
.then(() => console.log('MongoDB连接成功'))
.catch(err => console.error('MongoDB连接失败:', err));// 定义用户模式
const userSchema = new mongoose.Schema({name: {type: String,required: [true, '姓名不能为空'],trim: true,maxlength: [50, '姓名不能超过50个字符']},email: {type: String,required: [true, '邮箱不能为空'],unique: true,lowercase: true,match: [/^\w+@\w+\.\w+$/, '邮箱格式不正确']},age: {type: Number,min: [0, '年龄不能为负数'],max: [120, '年龄不能超过120']},createdAt: {type: Date,default: Date.now}
});// 添加索引
userSchema.index({ email: 1 }, { unique: true });// 实例方法
userSchema.methods.getFullInfo = function() {return `${this.name} (${this.email})`;
};// 静态方法
userSchema.statics.findByEmail = function(email) {return this.findOne({ email });
};const User = mongoose.model('User', userSchema);const app = express();
app.use(express.json());// 创建用户
app.post('/api/users', async (req, res) => {try {const user = new User(req.body);await user.save();res.status(201).json({message: '用户创建成功',user});} catch (error) {if (error.name === 'ValidationError') {const errors = Object.values(error.errors).map(e => e.message);return res.status(400).json({ errors });}if (error.code === 11000) {return res.status(400).json({ error: '邮箱已存在' });}res.status(500).json({ error: '服务器错误' });}
});// 获取所有用户
app.get('/api/users', async (req, res) => {try {const { page = 1, limit = 10, search } = req.query;const query = search ? { $or: [{ name: new RegExp(search, 'i') },{ email: new RegExp(search, 'i') }]} : {};const users = await User.find(query).limit(limit * 1).skip((page - 1) * limit).sort({ createdAt: -1 });const total = await User.countDocuments(query);res.json({users,pagination: {page: parseInt(page),limit: parseInt(limit),total,pages: Math.ceil(total / limit)}});} catch (error) {res.status(500).json({ error: '服务器错误' });}
});// 获取单个用户
app.get('/api/users/:id', async (req, res) => {try {const user = await User.findById(req.params.id);if (!user) {return res.status(404).json({ error: '用户不存在' });}res.json({ user });} catch (error) {res.status(500).json({ error: '服务器错误' });}
});app.listen(3000, () => {console.log('服务器运行在端口 3000');
});
6.2 MySQL集成(使用mysql2)
// 首先安装: npm install mysql2const mysql = require('mysql2/promise');
const express = require('express');// 创建数据库连接池
const pool = mysql.createPool({host: 'localhost',user: 'root',password: 'password',database: 'nodeapp',waitForConnections: true,connectionLimit: 10,queueLimit: 0
});// 数据库初始化
async function initDatabase() {try {await pool.execute(`CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50) NOT NULL,email VARCHAR(100) NOT NULL UNIQUE,age INT,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)`);console.log('数据库表创建成功');} catch (error) {console.error('数据库初始化失败:', error);}
}initDatabase();const app = express();
app.use(express.json());// 创建用户
app.post('/api/users', async (req, res) => {const { name, email, age } = req.body;try {const [result] = await pool.execute('INSERT INTO users (name, email, age) VALUES (?, ?, ?)',[name, email, age]);const [users] = await