Node.js 开发实战:从入门到精通
Node.js 开发详解
一、Node.js 核心知识框架
1.1 基础概念
- 什么是 Node.js:基于 Chrome V8 引擎构建的 JavaScript 运行环境
- 事件驱动架构:非阻塞 I/O 模型
- 单线程与事件循环:高效处理并发请求
- NPM(Node 包管理器):Node.js 的默认包管理工具
1.2 核心模块与 API
- 文件系统 (fs):文件操作
- HTTP/HTTPS:创建 Web 服务器
- 事件系统 (events):事件驱动编程
- 流 (stream):处理流式数据
- 路径 (path):处理文件路径
- 进程 (process):进程信息与控制
- 缓冲区 (buffer):处理二进制数据
- 操作系统 (os):获取操作系统信息
- 集群 (cluster):多进程能力
1.3 架构模式
- CommonJS 模块系统:Node.js 中的模块机制
- 回调函数与 Promise:异步处理方式
- Async/Await:现代化异步语法
- 中间件模式:Express 等框架的核心概念
1.4 Web 开发相关
- RESTful API 设计
- 数据库集成(MongoDB, MySQL, PostgreSQL)
- 身份验证与授权
- 错误处理机制
- 日志记录
Node.js 博客系统架构图
系统整体架构

用户认证流程
文章操作流程
Express 中间件执行顺序
graph LRA[Incoming Request] --> B[Application Level Middleware<br/>app.use(...)]B --> C[Route Middleware<br/>router.use(...)]C --> D[Route Handler<br/>app.get/post/put/delete]D --> E[Error Handling Middleware<br/>app.use(err, req, res, next)]E --> F[Response Sent to Client]
数据模型关系图
API 端点映射图
二、实战项目:简易博客系统
2.1 项目结构设计
blog-system/
├── app.js # 应用入口文件
├── package.json # 项目配置文件
├── routes/ # 路由目录
│ ├── posts.js # 文章路由
│ └── users.js # 用户路由
├── controllers/ # 控制器目录
│ ├── postController.js # 文章控制器
│ └── userController.js # 用户控制器
├── models/ # 数据模型目录
│ ├── Post.js # 文章模型
│ └── User.js # 用户模型
├── middleware/ # 中间件目录
│ └── auth.js # 认证中间件
└── utils/ # 工具函数目录└── database.js # 数据库连接
2.2 完整项目实现
package.json - 项目配置文件
{"name": "blog-system","version": "1.0.0","description": "A simple blog system built with Node.js","main": "app.js","scripts": {"start": "node app.js","dev": "nodemon app.js"},"dependencies": {"express": "^4.18.2","mongoose": "^7.5.0","bcryptjs": "^2.4.3","jsonwebtoken": "^9.0.2","cors": "^2.8.5","dotenv": "^16.3.1"},"devDependencies": {"nodemon": "^3.0.1"}
}
app.js - 应用入口文件
// 导入所需模块
const express = require('express');
const cors = require('cors');
require('dotenv').config();// 创建 Express 应用实例
const app = express();
const PORT = process.env.PORT || 3000;// 中间件配置
app.use(cors()); // 允许跨域请求
app.use(express.json()); // 解析 JSON 请求体
app.use(express.urlencoded({ extended: true })); // 解析 URL 编码的请求体// 导入路由
const postRoutes = require('./routes/posts');
const userRoutes = require('./routes/users');// 使用路由
app.use('/api/posts', postRoutes);
app.use('/api/users', userRoutes);// 根路径欢迎页面
app.get('/', (req, res) => {res.json({message: '欢迎使用博客系统 API',version: '1.0.0',endpoints: {posts: '/api/posts',users: '/api/users'}});
});// 错误处理中间件
app.use((err, req, res, next) => {console.error(err.stack);res.status(500).json({message: '服务器内部错误',error: process.env.NODE_ENV === 'development' ? err.message : {}});
});// 404 处理
app.use('*', (req, res) => {res.status(404).json({message: '页面未找到'});
});// 启动服务器
app.listen(PORT, () => {console.log(`服务器运行在端口 ${PORT}`);
});module.exports = app;
models/User.js - 用户数据模型
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');// 定义用户 Schema
const userSchema = new mongoose.Schema({username: {type: String,required: true,unique: true,trim: true,minlength: 3,maxlength: 30},email: {type: String,required: true,unique: true,trim: true,lowercase: true},password: {type: String,required: true,minlength: 6},createdAt: {type: Date,default: Date.now}
});// 密码加密中间件(保存前执行)
userSchema.pre('save', async function(next) {// 如果密码没有被修改,则跳过加密if (!this.isModified('password')) return next();try {// 对密码进行哈希加密const salt = await bcrypt.genSalt(10);this.password = await bcrypt.hash(this.password, salt);next();} catch (error) {next(error);}
});// 验证密码方法
userSchema.methods.comparePassword = async function(candidatePassword) {return await bcrypt.compare(candidatePassword, this.password);
};// 创建并导出 User 模型
module.exports = mongoose.model('User', userSchema);
models/Post.js - 文章数据模型
const mongoose = require('mongoose');// 定义文章 Schema
const postSchema = new mongoose.Schema({title: {type: String,required: true,trim: true,maxlength: 200},content: {type: String,required: true},author: {type: mongoose.Schema.Types.ObjectId,ref: 'User',required: true},tags: [{type: String,trim: true}],published: {type: Boolean,default: false},createdAt: {type: Date,default: Date.now},updatedAt: {type: Date,default: Date.now}
});// 更新时间中间件
postSchema.pre('save', function(next) {this.updatedAt = Date.now();next();
});// 创建并导出 Post 模型
module.exports = mongoose.model('Post', postSchema);
controllers/userController.js - 用户控制器
const User = require('../models/User');
const jwt = require('jsonwebtoken');// 生成 JWT token
const generateToken = (userId) => {return jwt.sign({ id: userId }, process.env.JWT_SECRET || 'default_secret', {expiresIn: '7d'});
};// 用户注册
exports.register = async (req, res) => {try {const { username, email, password } = req.body;// 检查必填字段if (!username || !email || !password) {return res.status(400).json({message: '用户名、邮箱和密码都是必需的'});}// 检查用户是否已存在const existingUser = await User.findOne({$or: [{ email }, { username }]});if (existingUser) {return res.status(400).json({message: '用户名或邮箱已被使用'});}// 创建新用户const user = new User({username,email,password});await user.save();// 生成 tokenconst token = generateToken(user._id);res.status(201).json({message: '用户注册成功',token,user: {id: user._id,username: user.username,email: user.email}});} catch (error) {res.status(500).json({message: '注册失败',error: error.message});}
};// 用户登录
exports.login = async (req, res) => {try {const { email, password } = req.body;// 检查必填字段if (!email || !password) {return res.status(400).json({message: '邮箱和密码都是必需的'});}// 查找用户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: '邮箱或密码错误'});}// 生成 tokenconst token = generateToken(user._id);res.json({message: '登录成功',token,user: {id: user._id,username: user.username,email: user.email}});} catch (error) {res.status(500).json({message: '登录失败',error: error.message});}
};// 获取当前用户信息
exports.getCurrentUser = async (req, res) => {try {const user = await User.findById(req.user.id).select('-password');res.json(user);} catch (error) {res.status(500).json({message: '获取用户信息失败',error: error.message});}
};
controllers/postController.js - 文章控制器
const Post = require('../models/Post');// 创建文章
exports.createPost = async (req, res) => {try {const { title, content, tags } = req.body;// 检查必填字段if (!title || !content) {return res.status(400).json({message: '标题和内容都是必需的'});}// 创建文章const post = new Post({title,content,tags: tags || [],author: req.user.id});await post.save();// 填充作者信息await post.populate('author', 'username email');res.status(201).json({message: '文章创建成功',post});} catch (error) {res.status(500).json({message: '创建文章失败',error: error.message});}
};// 获取所有文章
exports.getAllPosts = async (req, res) => {try {const page = parseInt(req.query.page) || 1;const limit = parseInt(req.query.limit) || 10;const skip = (page - 1) * limit;// 查询条件const query = {};if (req.query.published === 'true') {query.published = true;}// 获取文章列表const posts = await Post.find(query).populate('author', 'username').sort({ createdAt: -1 }).skip(skip).limit(limit);// 获取总数const total = await Post.countDocuments(query);res.json({posts,pagination: {current: page,pages: Math.ceil(total / limit),total}});} catch (error) {res.status(500).json({message: '获取文章列表失败',error: error.message});}
};// 获取单篇文章
exports.getPostById = async (req, res) => {try {const post = await Post.findById(req.params.id).populate('author', 'username email');if (!post) {return res.status(404).json({message: '文章不存在'});}res.json(post);} catch (error) {res.status(500).json({message: '获取文章失败',error: error.message});}
};// 更新文章
exports.updatePost = async (req, res) => {try {const { title, content, tags, published } = req.body;// 查找文章const post = await Post.findById(req.params.id);if (!post) {return res.status(404).json({message: '文章不存在'});}// 检查权限(只有作者可以更新)if (post.author.toString() !== req.user.id) {return res.status(403).json({message: '无权修改此文章'});}// 更新文章post.title = title || post.title;post.content = content || post.content;post.tags = tags || post.tags;if (published !== undefined) {post.published = published;}await post.save();// 填充作者信息await post.populate('author', 'username email');res.json({message: '文章更新成功',post});} catch (error) {res.status(500).json({message: '更新文章失败',error: error.message});}
};// 删除文章
exports.deletePost = async (req, res) => {try {const post = await Post.findById(req.params.id);if (!post) {return res.status(404).json({message: '文章不存在'});}// 检查权限(只有作者可以删除)if (post.author.toString() !== req.user.id) {return res.status(403).json({message: '无权删除此文章'});}await Post.findByIdAndDelete(req.params.id);res.json({message: '文章删除成功'});} catch (error) {res.status(500).json({message: '删除文章失败',error: error.message});}
};
middleware/auth.js - 认证中间件
const jwt = require('jsonwebtoken');
const User = require('../models/User');// 认证中间件
const auth = async (req, res, next) => {try {// 从请求头获取 tokenconst token = req.header('Authorization')?.replace('Bearer ', '');if (!token) {return res.status(401).json({message: '访问被拒绝,未提供认证令牌'});}// 验证 tokenconst decoded = jwt.verify(token, process.env.JWT_SECRET || 'default_secret');// 查找用户const user = await User.findById(decoded.id).select('-password');if (!user) {return res.status(401).json({message: '认证失败,用户不存在'});}// 将用户信息添加到请求对象req.user = user;next();} catch (error) {res.status(401).json({message: '认证令牌无效'});}
};module.exports = auth;
routes/users.js - 用户路由
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
const auth = require('../middleware/auth');// 注册路由 POST /api/users/register
router.post('/register', userController.register);// 登录路由 POST /api/users/login
router.post('/login', userController.login);// 获取当前用户信息 GET /api/users/me (需要认证)
router.get('/me', auth, userController.getCurrentUser);module.exports = router;
routes/posts.js - 文章路由
const express = require('express');
const router = express.Router();
const postController = require('../controllers/postController');
const auth = require('../middleware/auth');// 创建文章 POST /api/posts (需要认证)
router.post('/', auth, postController.createPost);// 获取所有文章 GET /api/posts
router.get('/', postController.getAllPosts);// 获取单篇文章 GET /api/posts/:id
router.get('/:id', postController.getPostById);// 更新文章 PUT /api/posts/:id (需要认证)
router.put('/:id', auth, postController.updatePost);// 删除文章 DELETE /api/posts/:id (需要认证)
router.delete('/:id', auth, postController.deletePost);module.exports = router;
三、常用 API 详解
3.1 Express 核心 API
应用级方法
// 创建 Express 应用
const express = require('express');
const app = express();// GET 请求
app.get('/', (req, res) => {res.send('Hello World!');
});// POST 请求
app.post('/users', (req, res) => {res.send('Create a user');
});// PUT 请求
app.put('/users/:id', (req, res) => {res.send('Update a user');
});// DELETE 请求
app.delete('/users/:id', (req, res) => {res.send('Delete a user');
});// 所有 HTTP 方法
app.all('/secret', (req, res, next) => {console.log('Accessing the secret section ...');next(); // 传递控制权到下一个处理器
});
路由参数
// 基本路由参数
app.get('/users/:userId/books/:bookId', (req, res) => {res.send(req.params); // { userId: '123', bookId: '456' }
});// 正则表达式路由参数
app.get('/user/:userId(\\d+)', (req, res) => {res.send(`User ID: ${req.params.userId}`);
});
中间件使用
// 应用级中间件
app.use((req, res, next) => {console.log('Time:', Date.now());next();
});// 路径特定中间件
app.use('/user/:id', (req, res, next) => {console.log('Request Type:', req.method);next();
});// 错误处理中间件(必须有4个参数)
app.use((err, req, res, next) => {console.error(err.stack);res.status(500).send('Something broke!');
});
3.2 文件系统 (fs) API
读取文件
const fs = require('fs');// 异步读取文件
fs.readFile('example.txt', 'utf8', (err, data) => {if (err) throw err;console.log(data);
});// 同步读取文件
try {const data = fs.readFileSync('example.txt', 'utf8');console.log(data);
} catch (err) {console.error(err);
}// Promise 方式读取文件
const fsPromises = require('fs').promises;async function readFileAsync() {try {const data = await fsPromises.readFile('example.txt', 'utf8');console.log(data);} catch (err) {console.error(err);}
}
写入文件
const fs = require('fs');// 异步写入文件
fs.writeFile('message.txt', 'Hello Node.js', (err) => {if (err) throw err;console.log('文件已保存!');
});// 同步写入文件
try {fs.writeFileSync('message.txt', 'Hello Node.js');console.log('文件已保存!');
} catch (err) {console.error(err);
}// 追加内容到文件
fs.appendFile('message.txt', '追加的数据', (err) => {if (err) throw err;console.log('数据已追加到文件');
});
3.3 HTTP 模块 API
创建 HTTP 服务器
const http = require('http');// 创建简单服务器
const server = http.createServer((req, res) => {res.statusCode = 200;res.setHeader('Content-Type', 'text/plain');res.end('Hello World\n');
});server.listen(3000, '127.0.0.1', () => {console.log('服务器运行在 http://127.0.0.1:3000/');
});
处理不同请求方法
const http = require('http');
const url = require('url');const server = http.createServer((req, res) => {const parsedUrl = url.parse(req.url, true);const path = parsedUrl.pathname;const method = req.method;// 设置响应头res.setHeader('Content-Type', 'application/json');if (method === 'GET' && path === '/api/users') {res.statusCode = 200;res.end(JSON.stringify({ message: 'Get all users' }));} else if (method === 'POST' && path === '/api/users') {let body = '';req.on('data', chunk => {body += chunk.toString();});req.on('end', () => {console.log(body);res.statusCode = 201;res.end(JSON.stringify({ message: 'User created' }));});} else {res.statusCode = 404;res.end(JSON.stringify({ message: 'Not Found' }));}
});server.listen(3000);
3.4 事件系统 (events) API
EventEmitter 基本使用
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 });
一次性监听器
const EventEmitter = require('events');
const myEmitter = new EventEmitter();// 只会触发一次
myEmitter.once('firstConnection', () => {console.log('第一次连接!');
});myEmitter.emit('firstConnection'); // 输出: 第一次连接!
myEmitter.emit('firstConnection'); // 不输出任何内容
3.5 流 (stream) API
可读流
const fs = require('fs');// 创建可读流
const readableStream = fs.createReadStream('large-file.txt');readableStream.on('data', (chunk) => {console.log(`接收到 ${chunk.length} 字节的数据`);
});readableStream.on('end', () => {console.log('数据读取完成');
});readableStream.on('error', (err) => {console.error('发生错误:', err);
});
可写流
const fs = require('fs');// 创建可写流
const writableStream = fs.createWriteStream('output.txt');writableStream.write('Hello ');
writableStream.write('World!\n');
writableStream.end();writableStream.on('finish', () => {console.log('写入完成');
});
管道流
const fs = require('fs');// 使用管道将可读流连接到可写流
const readable = fs.createReadStream('input.txt');
const writable = fs.createWriteStream('output.txt');readable.pipe(writable);// 链式管道
const zlib = require('zlib');
const gzip = zlib.createGzip();readable.pipe(gzip).pipe(fs.createWriteStream('output.txt.gz'));
四、总结
Node.js 是一个功能强大的 JavaScript 运行环境,适用于构建各种类型的服务器端应用程序。通过上述详细介绍和实际项目示例,我们可以看到:
- 核心概念清晰:事件驱动、非阻塞 I/O 是 Node.js 的核心优势
- 生态系统丰富:npm 提供了大量的第三方包
- 开发效率高:统一的语言栈减少上下文切换
- 性能优秀:适合 I/O 密集型应用
通过构建完整的博客系统项目,我们掌握了:
- RESTful API 设计原则
- 数据库集成(MongoDB)
- 用户认证与授权
- 错误处理机制
- 中间件模式的应用
这些知识点构成了 Node.js 开发的基础,为更复杂的项目开发打下了坚实的基础。
