Express.js 教程
1. 项目概述
Express.js 是基于 Node.js 的快速、无偏见、极简的 Web 框架,为构建 Web 应用和 API 提供了强大的功能。它是 Node.js 生态系统中最流行的 Web 框架之一,被广泛用于构建各种规模的后端服务。
1.1 主要特性
- 轻量级设计:核心功能精简,通过中间件扩展功能
- 灵活的路由系统:支持 RESTful API 设计
- 强大的中间件支持:可自定义和使用第三方中间件
- 模板引擎集成:支持多种模板引擎
- 错误处理机制:内置错误处理
- 静态文件服务:方便提供静态资源
- 生态系统丰富:拥有大量第三方模块
1.2 适用场景
- 构建 RESTful API
- Web 应用后端开发
- 微服务架构
- 实时应用(结合 Socket.io)
- 原型开发和快速迭代
2. 安装与设置
2.1 环境要求
- Node.js 14.0 或更高版本
- npm 或 yarn 包管理器
2.2 安装步骤
方法一:使用 Express 生成器
# 全局安装 Express 生成器
npm install -g express-generator
# 创建项目
express my-express-app
# 进入项目目录
cd my-express-app
# 安装依赖
npm install方法二:手动创建项目
# 创建项目目录
mkdir my-express-app
cd my-express-app
# 初始化项目
npm init -y
# 安装 Express
npm install express2.3 基本项目结构
my-express-app/
├── node_modules/
├── public/ # 静态资源
├── routes/ # 路由文件
├── views/ # 模板文件
├── app.js # 应用主文件
├── package.json # 项目配置
└── package-lock.json # 依赖锁定3. 核心概念
3.1 应用实例
Express 应用是通过 express() 函数创建的,它是整个应用的核心。
const express = require('express');
const app = express();
// 启动服务器
app.listen(3000, () => {
console.log('Server running on port 3000');
});3.2 路由
路由定义了应用如何响应客户端对特定端点的请求,包括 URL 和 HTTP 请求方法。
// 基本路由
app.get('/', (req, res) => {
res.send('Hello World!');
});
// 带参数的路由
app.get('/users/:id', (req, res) => {
res.send(`User ID: ${req.params.id}`);
});
// 处理 POST 请求
app.post('/users', (req, res) => {
// 处理用户创建逻辑
res.send('User created');
});3.3 中间件
中间件函数是可以访问请求对象 (req)、响应对象 (res) 和应用程序请求-响应循环中的下一个中间件函数的函数。
// 自定义中间件
const logger = (req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next(); // 调用下一个中间件
};
// 使用中间件
app.use(logger);
// 内置中间件
app.use(express.json()); // 解析 JSON 请求体
app.use(express.urlencoded({ extended: true })); // 解析 URL 编码的请求体
app.use(express.static('public')); // 提供静态文件3.4 请求对象 (req)
请求对象包含了客户端请求的所有信息。
app.get('/profile', (req, res) => {
console.log(req.params); // 路由参数
console.log(req.query); // 查询字符串参数
console.log(req.body); // 请求体
console.log(req.headers); // 请求头
console.log(req.method); // HTTP 方法
console.log(req.url); // 请求 URL
res.send('Profile page');
});3.5 响应对象 (res)
响应对象用于向客户端发送响应。
app.get('/data', (req, res) => {
// 发送文本响应
res.send('Hello');
// 发送 JSON 响应
res.json({ name: 'John', age: 30 });
// 发送文件
res.sendFile(__dirname + '/index.html');
// 设置状态码
res.status(404).send('Not Found');
// 重定向
res.redirect('/home');
});4. 基本使用
4.1 创建简单的 Web 服务器
const express = require('express');
const app = express();
const port = 3000;
// 根路由
app.get('/', (req, res) => {
res.send('Hello Express!');
});
// 启动服务器
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});4.2 构建 RESTful API
const express = require('express');
const app = express();
// 中间件
app.use(express.json());
// 模拟数据库
let users = [
{ id: 1, name: 'John', email: 'john@example.com' },
{ id: 2, name: 'Jane', email: 'jane@example.com' }
];
// GET 所有用户
app.get('/api/users', (req, res) => {
res.json(users);
});
// GET 单个用户
app.get('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) return res.status(404).send('User not found');
res.json(user);
});
// POST 创建用户
app.post('/api/users', (req, res) => {
const newUser = {
id: users.length + 1,
name: req.body.name,
email: req.body.email
};
users.push(newUser);
res.status(201).json(newUser);
});
// PUT 更新用户
app.put('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) return res.status(404).send('User not found');
user.name = req.body.name;
user.email = req.body.email;
res.json(user);
});
// DELETE 删除用户
app.delete('/api/users/:id', (req, res) => {
const userIndex = users.findIndex(u => u.id === parseInt(req.params.id));
if (userIndex === -1) return res.status(404).send('User not found');
users.splice(userIndex, 1);
res.status(204).send();
});
app.listen(3000, () => console.log('Server running on port 3000'));4.3 组织路由
使用路由模块
// routes/users.js
const express = require('express');
const router = express.Router();
// 模拟数据
let users = [/* 用户数据 */];
// 路由处理
router.get('/', (req, res) => {
res.json(users);
});
// 其他路由...
module.exports = router;在主应用中使用
// app.js
const express = require('express');
const app = express();
const usersRouter = require('./routes/users');
// 使用路由
app.use('/api/users', usersRouter);
app.listen(3000);5. 高级功能
5.1 中间件开发
创建自定义中间件
// middleware/auth.js
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ message: 'Access denied' });
}
// 验证 token...
next();
};
module.exports = authMiddleware;使用中间件
const authMiddleware = require('./middleware/auth');
// 应用于所有路由
app.use(authMiddleware);
// 应用于特定路由
app.get('/protected', authMiddleware, (req, res) => {
res.send('Protected route');
});5.2 错误处理
全局错误处理中间件
// 404 错误处理
app.use((req, res, next) => {
res.status(404).json({ message: 'Route not found' });
});
// 全局错误处理
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ message: 'Internal server error' });
});5.3 环境配置
使用 dotenv 管理环境变量
npm install dotenv// .env
PORT=3000
DATABASE_URL=mongodb://localhost:27017/myapp// app.js
require('dotenv').config();
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});5.4 数据库集成
集成 MongoDB(使用 Mongoose)
npm install mongooseconst mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://localhost:27017/myapp')
.then(() => console.log('Connected to MongoDB'))
.catch(err => console.error('MongoDB connection error:', err));
// 定义模型
const User = mongoose.model('User', {
name: String,
email: String
});
// 使用模型
app.get('/users', async (req, res) => {
const users = await User.find();
res.json(users);
});6. 实用案例
6.1 构建博客 API
项目结构
blog-api/
├── app.js
├── routes/
│ ├── posts.js
│ └── users.js
├── models/
│ ├── Post.js
│ └── User.js
└── package.json核心代码
// models/Post.js
const mongoose = require('mongoose');
const postSchema = new mongoose.Schema({
title: String,
content: String,
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
createdAt: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('Post', postSchema);// routes/posts.js
const express = require('express');
const router = express.Router();
const Post = require('../models/Post');
// 获取所有文章
router.get('/', async (req, res) => {
const posts = await Post.find().populate('author');
res.json(posts);
});
// 创建文章
router.post('/', async (req, res) => {
const post = new Post({
title: req.body.title,
content: req.body.content,
author: req.body.authorId
});
await post.save();
res.status(201).json(post);
});
// 其他路由...
module.exports = router;6.2 实现文件上传
安装依赖
npm install multer实现代码
const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
// 配置存储
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
cb(null, Date.now() + path.extname(file.originalname));
}
});
// 创建上传中间件
const upload = multer({ storage: storage });
// 确保上传目录存在
const fs = require('fs');
if (!fs.existsSync('uploads')) {
fs.mkdirSync('uploads');
}
// 提供静态文件
app.use('/uploads', express.static('uploads'));
// 文件上传路由
app.post('/upload', upload.single('file'), (req, res) => {
res.json({
message: 'File uploaded successfully',
file: req.file
});
});
// 多文件上传
app.post('/upload-multiple', upload.array('files', 5), (req, res) => {
res.json({
message: 'Files uploaded successfully',
files: req.files
});
});
app.listen(3000);7. 性能优化
7.1 代码优化
- 使用路由模块化:将路由分离到不同文件
- 合理使用中间件:只在需要的地方使用中间件
- 避免同步操作:使用异步函数和 Promise
- 优化数据库查询:使用索引和分页
7.2 服务器配置
- 启用压缩:使用
compression中间件 - 设置缓存头:为静态文件设置合理的缓存
- 使用 HTTPS:提高安全性和 SEO
- 配置 CORS:根据需要设置跨域资源共享
7.3 监控与调试
- 使用 Morgan 日志:记录请求信息
- 实现请求计时:监控响应时间
- 错误日志记录:捕获和记录错误
- 使用 PM2 管理进程:实现负载均衡和自动重启
8. 最佳实践
8.1 代码组织
- 模块化设计:将功能分离到不同模块
- 一致的命名规范:使用清晰的命名
- 代码注释:为复杂逻辑添加注释
- 版本控制:使用 Git 管理代码
8.2 安全措施
- 输入验证:验证所有用户输入
- 防止 SQL 注入:使用参数化查询或 ORM
- 防止 XSS 攻击:转义输出
- 使用 Helmet:设置安全相关的 HTTP 头
- 密码加密:使用 bcrypt 等库
8.3 部署建议
- 使用环境变量:分离配置和代码
- 使用 Docker:容器化部署
- 持续集成/持续部署:自动化测试和部署
- 监控系统:使用工具监控应用状态
9. 常见问题与解决方案
9.1 路由冲突
问题:路由顺序导致某些路由不被触发
解决方案:
- 确保更具体的路由在前面
- 使用
app.use()时注意路径匹配
9.2 中间件执行顺序
问题:中间件执行顺序不符合预期
解决方案:
- 按照正确的顺序注册中间件
- 理解中间件的执行流程
9.3 CORS 错误
问题:跨域请求被阻止
解决方案:
- 使用
cors中间件 - 手动设置 CORS 头
9.4 内存泄漏
问题:应用内存使用持续增长
解决方案:
- 避免全局变量累积
- 正确关闭数据库连接
- 使用内存分析工具
10. 参考资源
10.1 官方文档
10.2 学习资源
10.3 第三方模块
- Multer - 文件上传
- Passport - 认证
- Winston - 日志
- Nodemailer - 邮件发送
- Sharp - 图像处理
10.4 工具与服务
11. 总结
Express.js 是一个轻量级但功能强大的 Node.js Web 框架,它的设计理念是 "少即是多",通过简洁的 API 提供了构建 Web 应用所需的核心功能。它的灵活性和可扩展性使其成为 Node.js 生态系统中最受欢迎的 Web 框架之一。
通过本教程,你应该已经掌握了 Express.js 的基本使用方法和高级功能,包括:
- 项目创建和配置
- 路由和中间件
- RESTful API 构建
- 数据库集成
- 文件上传
- 错误处理
- 性能优化
- 最佳实践
Express.js 适合从简单的个人项目到复杂的企业级应用的各种场景。结合其丰富的生态系统和活跃的社区,它可以帮助你快速构建高性能、可维护的 Web 应用后端。
随着你对 Express.js 的深入了解,你会发现它不仅是一个 Web 框架,更是一种构建 Web 应用的思想和方法论。希望本教程对你的学习和开发有所帮助!