Node.js让JavaScript不再局限于浏览器,成为了全栈开发的强大工具。今天分享Node.js后端开发的完整学习路径。
🚀 Node.js基础
什么是Node.js
Node.js是一个基于Chrome V8引擎的JavaScript运行环境,让JavaScript能够在服务器端运行。
核心特性:
- 🔄 事件驱动:非阻塞I/O模型
- ⚡ 高性能:适合I/O密集型应用
- 📦 NPM生态:丰富的第三方包
- 🌐 跨平台:Windows、macOS、Linux
环境搭建
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 安装Node.js(推荐使用nvm管理版本)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install node
nvm use node
# 验证安装
node --version
npm --version
# 创建项目
mkdir my-node-app
cd my-node-app
npm init -y
|
📊 Express框架入门
快速开始
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| const express = require('express');
const app = express();
const port = 3000;
// 中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// 路由
app.get('/', (req, res) => {
res.json({ message: 'Hello World!' });
});
app.listen(port, () => {
console.log(`服务器运行在 http://localhost:${port}`);
});
|
中间件系统
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // 日志中间件
const logger = (req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next();
};
// 错误处理中间件
const errorHandler = (err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
};
// 应用中间件
app.use(logger);
app.use('/api', apiRoutes);
app.use(errorHandler);
|
路由设计
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| const router = express.Router();
// RESTful API设计
router.get('/users', getAllUsers); // 获取所有用户
router.get('/users/:id', getUserById); // 获取单个用户
router.post('/users', createUser); // 创建用户
router.put('/users/:id', updateUser); // 更新用户
router.delete('/users/:id', deleteUser); // 删除用户
// 路由处理函数
const getAllUsers = async (req, res) => {
try {
const users = await User.find();
res.json(users);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
module.exports = router;
|
🗄️ 数据库集成
MongoDB + Mongoose
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
| const mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://localhost:27017/myapp', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// 定义Schema
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
email: {
type: String,
required: true,
unique: 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();
const bcrypt = require('bcrypt');
this.password = await bcrypt.hash(this.password, 12);
next();
});
const User = mongoose.model('User', userSchema);
|
数据库操作
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 createUser = async (userData) => {
try {
const user = new User(userData);
await user.save();
return user;
} catch (error) {
throw error;
}
};
// 查询用户
const findUsers = async (filter = {}) => {
return await User.find(filter)
.select('-password')
.sort({ createdAt: -1 });
};
// 更新用户
const updateUser = async (id, updateData) => {
return await User.findByIdAndUpdate(
id,
updateData,
{ new: true, runValidators: true }
);
};
|
🔐 身份验证与授权
JWT身份验证
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
| const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
// 生成JWT Token
const generateToken = (userId) => {
return jwt.sign({ userId }, process.env.JWT_SECRET, {
expiresIn: '7d'
});
};
// 登录功能
const login = async (req, res) => {
try {
const { email, password } = req.body;
// 查找用户
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({ error: '邮箱或密码错误' });
}
// 验证密码
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(401).json({ error: '邮箱或密码错误' });
}
// 生成token
const token = generateToken(user._id);
res.json({
message: '登录成功',
token,
user: {
id: user._id,
name: user.name,
email: user.email
}
});
} catch (error) {
res.status(500).json({ error: error.message });
}
};
|
认证中间件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| const authenticate = async (req, res, next) => {
try {
const token = req.header('Authorization')?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({ error: '访问被拒绝,需要token' });
}
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findById(decoded.userId);
if (!user) {
return res.status(401).json({ error: '用户不存在' });
}
req.user = user;
next();
} catch (error) {
res.status(401).json({ error: 'Token无效' });
}
};
// 使用认证中间件
app.use('/api/protected', authenticate);
|
📝 API设计最佳实践
RESTful API规范
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
| // 统一响应格式
const sendResponse = (res, statusCode, data, message) => {
res.status(statusCode).json({
success: statusCode < 400,
message,
data,
timestamp: new Date().toISOString()
});
};
// API版本控制
app.use('/api/v1', v1Routes);
app.use('/api/v2', v2Routes);
// 参数验证中间件
const validateUser = (req, res, next) => {
const { name, email, password } = req.body;
if (!name || !email || !password) {
return sendResponse(res, 400, null, '缺少必要参数');
}
if (password.length < 6) {
return sendResponse(res, 400, null, '密码长度至少6位');
}
next();
};
|
分页和排序
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
| const getPaginatedUsers = async (req, res) => {
try {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
const sort = req.query.sort || 'createdAt';
const order = req.query.order === 'asc' ? 1 : -1;
const skip = (page - 1) * limit;
const users = await User.find()
.select('-password')
.sort({ [sort]: order })
.skip(skip)
.limit(limit);
const total = await User.countDocuments();
res.json({
users,
pagination: {
currentPage: page,
totalPages: Math.ceil(total / limit),
totalItems: total,
itemsPerPage: limit
}
});
} catch (error) {
res.status(500).json({ error: error.message });
}
};
|
🔧 实用工具和中间件
环境配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // .env文件
const dotenv = require('dotenv');
dotenv.config();
// config/database.js
module.exports = {
development: {
url: process.env.DEV_DB_URL,
options: {
useNewUrlParser: true,
useUnifiedTopology: true
}
},
production: {
url: process.env.PROD_DB_URL,
options: {
useNewUrlParser: true,
useUnifiedTopology: true,
ssl: true
}
}
};
|
文件上传
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
| const multer = require('multer');
const path = require('path');
// 配置存储
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
}
});
const upload = multer({
storage,
limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
fileFilter: (req, file, cb) => {
const allowedTypes = /jpeg|jpg|png|gif/;
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = allowedTypes.test(file.mimetype);
if (mimetype && extname) {
return cb(null, true);
} else {
cb(new Error('只允许上传图片文件'));
}
}
});
// 使用文件上传
app.post('/api/upload', upload.single('image'), (req, res) => {
if (!req.file) {
return res.status(400).json({ error: '没有文件上传' });
}
res.json({
message: '文件上传成功',
filename: req.file.filename,
path: req.file.path
});
});
|
日志系统
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
new winston.transports.File({ filename: 'logs/combined.log' })
]
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}
module.exports = logger;
|
🧪 测试
单元测试
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 request = require('supertest');
const app = require('../app');
describe('User API', () => {
describe('POST /api/users', () => {
it('should create a new user', async () => {
const userData = {
name: 'Test User',
email: 'test@example.com',
password: 'password123'
};
const response = await request(app)
.post('/api/users')
.send(userData)
.expect(201);
expect(response.body.user.name).toBe(userData.name);
expect(response.body.user.email).toBe(userData.email);
});
it('should return 400 if required fields are missing', async () => {
const response = await request(app)
.post('/api/users')
.send({})
.expect(400);
expect(response.body.success).toBe(false);
});
});
});
|
🚀 部署和优化
PM2进程管理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 安装PM2
npm install -g pm2
# 启动应用
pm2 start app.js --name "my-app"
# 集群模式
pm2 start app.js -i max
# 监控
pm2 monitor
# 日志查看
pm2 logs
|
性能优化
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
| // 启用gzip压缩
const compression = require('compression');
app.use(compression());
// 设置安全headers
const helmet = require('helmet');
app.use(helmet());
// 限制请求频率
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100 // 限制每个IP 100次请求
});
app.use(limiter);
// 缓存
const redis = require('redis');
const client = redis.createClient();
const cache = (duration) => {
return async (req, res, next) => {
const key = req.originalUrl;
const cached = await client.get(key);
if (cached) {
return res.json(JSON.parse(cached));
}
res.sendResponse = res.json;
res.json = (body) => {
client.setex(key, duration, JSON.stringify(body));
res.sendResponse(body);
};
next();
};
};
|
📊 推荐学习资源
📚 书籍推荐
- 《Node.js实战》 - 全面的Node.js指南
- 《深入浅出Node.js》 - 朴灵著,深入理解Node.js原理
🔧 实用工具
- Postman - API测试工具
- MongoDB Compass - 可视化数据库管理
- VS Code - 最佳Node.js开发环境
📦 常用包推荐
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| {
"dependencies": {
"express": "^4.18.2",
"mongoose": "^6.8.0",
"bcrypt": "^5.1.0",
"jsonwebtoken": "^8.5.1",
"dotenv": "^16.0.3",
"cors": "^2.8.5",
"helmet": "^6.0.1",
"compression": "^1.7.4"
},
"devDependencies": {
"nodemon": "^2.0.20",
"jest": "^29.3.1",
"supertest": "^6.3.3"
}
}
|
💡 总结
Node.js后端开发的核心要点:
- 掌握基础概念 - 事件循环、模块系统、异步编程
- 熟练使用Express - 路由、中间件、错误处理
- 数据库操作 - MongoDB/MySQL + ORM/ODM
- 身份验证 - JWT、Session、OAuth
- API设计 - RESTful、GraphQL
- 测试和部署 - 单元测试、集成测试、CI/CD
记住,后端开发不只是写代码,还要考虑安全性、性能、可维护性等方面。持续学习,关注最新技术动态!
你在Node.js开发中遇到过哪些挑战?欢迎在评论区分享经验!