Express 框架从入门到生产实践:路由、中间件与安全配置
Node.js 的 Express 框架是目前最流行的 Web 框架之一,其简洁的路由机制和中间件体系为构建 RESTful API 和 Web 应用提供了坚实基础。本文从零开始,逐步深入,涵盖基础路由、模块化路由、中间件分类与自定义、统一错误处理、文件上传、安全防护以及性能优化等生产级实践,所有代码基于 Express 4.x 版本。// 第一个 Express 应用
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 on http://localhost:${PORT}`);
});
核心解析:express() 创建应用实例,封装 HTTP 服务器逻辑;app.get(path, handler) 定义 GET 请求路由;res.send() 自动设置 Content-Type。
一、路由:HTTP 方法与参数处理
Express 支持所有标准 HTTP 方法:GET、POST、PUT、DELETE 等。路由参数通过冒号定义,存储在 req.params;查询字符串通过 req.query 获取。
// 基本路由示例
app.get('/users', (req, res) => { res.json({ users: ['Alice', 'Bob'] }); });
app.post('/users', (req, res) => { res.status(201).json({ message: 'User created' }); });
app.put('/users/:id', (req, res) => { res.json({ message: `User ${req.params.id} updated` }); });
app.delete('/users/:id', (req, res) => { res.json({ message: `User ${req.params.id} deleted` }); });
// 路由参数与查询字符串
app.get('/users/:id/posts', (req, res) => {
const { id } = req.params;
const { page = 1, limit = 10 } = req.query;
res.json({ userId: id, page, limit });
});
二、路由模块化:express.Router()
当路由增多时,使用 Router 将代码按模块拆分。
// routes/users.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => res.json({ users: [] }));
router.get('/:id', (req, res) => res.json({ user: req.params.id }));
module.exports = router;
// app.js 主文件
const userRouter = require('./routes/users');
app.use('/users', userRouter);
此外,app.route() 可对同一资源链式定义多个 HTTP 方法,减少重复代码。
三、中间件:Express 的灵魂
中间件函数可访问 req、res 和 next,按执行顺序分为应用级、路由级、错误处理、内置与第三方中间件。
1. 常用内置中间件
express.json() 解析 JSON 请求体,express.urlencoded() 解析 URL 编码请求体,express.static() 托管静态文件。
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static('public'));
2. 自定义应用级中间件
通过 app.use() 定义全局或路径特定的中间件,一定调用 next() 否则请求挂起。
app.use((req, res, next) => {
console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
next();
});
3. 错误处理中间件
必须有 4 个参数 (err, req, res, next),且位于所有中间件和路由之后。
app.get('/error', (req, res, next) => {
const error = new Error('Something went wrong!');
error.status = 500;
next(error);
});
app.use((err, req, res, next) => {
const status = err.status || 500;
const message = err.message || 'Internal Server Error';
res.status(status).json({ error: message });
});
四、统一错误处理:同步与异步错误
Express 4.x 默认不捕获 async/await 中的错误,需手动包装。
定义统一错误类:
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
创建异步包装器:
const asyncWrapper = (fn) => {
return (req, res, next) => {
fn(req, res, next).catch(next);
};
};
使用示例:
app.get('/users/:id', asyncWrapper(async (req, res, next) => {
const user = await User.findById(req.params.id);
if (!user) throw new AppError('User not found', 404);
res.json({ user });
}));
错误处理中间件区分业务错误与系统错误,可仅在开发环境返回堆栈:
app.use((err, req, res, next) => {
const { statusCode = 500, message, isOperational } = err;
res.status(statusCode).json({
error: isOperational ? message : 'Internal Server Error',
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
});
});
五、RESTful API 设计实践
资源导向,HTTP 方法对应 CRUD。以用户管理为例:
let users = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' }
];
app.get('/users', asyncWrapper(async (req, res) => {
const { page = 1, limit = 10 } = req.query;
const start = (page - 1) * limit;
const end = start + parseInt(limit);
const paginatedUsers = users.slice(start, end);
res.json({ data: paginatedUsers, page: parseInt(page), limit: parseInt(limit), total: users.length });
}));
app.post('/users', asyncWrapper(async (req, res, next) => {
const { name, email } = req.body;
if (!name || !email) throw new AppError('Name and email are required', 400);
const newUser = { id: users.length + 1, name, email };
users.push(newUser);
res.status(201).json({ data: newUser });
}));
六、文件上传:Multer 中间件
Multer 处理 multipart/form-data。
const multer = require('multer');
const storage = multer.diskStorage({
destination: (req, file, cb) => { cb(null, 'uploads/'); },
filename: (req, file, cb) => { cb(null, `${Date.now()}-${file.originalname}`); }
});
const fileFilter = (req, file, cb) => {
if (file.mimetype.startsWith('image/')) cb(null, true);
else cb(new AppError('Only images are allowed', 400), false);
};
const upload = multer({ storage, fileFilter, limits: { fileSize: 5 * 1024 * 1024 } });
// 单文件上传
app.post('/upload/avatar', upload.single('avatar'), (req, res) => {
res.json({ message: 'Avatar uploaded', file: req.file });
});
// 多文件上传
app.post('/upload/photos', upload.array('photos', 5), (req, res) => {
res.json({ message: 'Photos uploaded', files: req.files });
});
七、安全最佳实践
1. Helmet:设置安全 HTTP 头
const helmet = require('helmet');
app.use(helmet());
2. CORS:跨域资源共享
const cors = require('cors');
// 允许所有来源(开发)
app.use(cors());
// 或限制特定来源(生产)
app.use(cors({ origin: 'https://your-frontend.com', methods: ['GET','POST','PUT','DELETE'] }));
3. 速率限制:防止暴力攻击
const rateLimit = require('express-rate-limit');
const globalLimiter = rateLimit({ windowMs: 15*60*1000, max: 100 });
app.use(globalLimiter);
// 登录接口更严格
const loginLimiter = rateLimit({ windowMs: 15*60*1000, max: 5 });
app.post('/login', loginLimiter, (req, res) => res.json({ message: 'Login' }));
4. 输入验证:使用 Joi
const Joi = require('joi');
const userSchema = Joi.object({
name: Joi.string().min(2).max(30).required(),
email: Joi.string().email().required(),
age: Joi.number().integer().min(18).max(100)
});
app.post('/users', (req, res, next) => {
const { error } = userSchema.validate(req.body);
if (error) throw new AppError(error.details.message, 400);
next();
}, (req, res) => {
res.json({ message: 'User created' });
});
八、性能优化
1. 压缩响应
const compression = require('compression');
app.use(compression());
2. 静态文件缓存
app.use(express.static('public', { maxAge: '1d' }));
3. 避免同步操作
所有 I/O 应使用异步方式(数据库查询、文件读写等),防止阻塞事件循环。
以上实践涵盖了从基础到生产级的 Express 开发要点,开发者可根据项目需求灵活组合各项中间件与配置。
Re: Express 框架从入门到生产实践:路由、中间件与安全配置
感谢楼主分享这么详细的 Express 实践指南!从基础路由到模块化拆分,再到中间件和统一错误处理,结构清晰,代码也很规范。特别是 `asyncWrapper` 这部分,对于刚接触 Express 的新手来说非常实用,能避免很多异步错误漏捕获的问题。想请教下,在生产环境中处理文件上传时,除了 `multer` 中间件,还有没有推荐的安全检查或配置技巧?Re: Express 框架从入门到生产实践:路由、中间件与安全配置
感谢楼主这么详细的教程!从基础路由到中间件、错误处理,再到生产化的安全配置思路,脉络很清晰。对于刚接触 Express 的新手来说,这样一步步拆解非常友好,尤其“统一错误处理”和“异步包装器”这部分是很多教程容易忽略的坑,楼主写得特别实用。期待后续看到更多关于安全配置和性能优化的内容~Re: Express 框架从入门到生产实践:路由、中间件与安全配置
楼主总结得很全面!尤其喜欢统一错误处理的 `AppError` 类和 `asyncWrapper`,这在生产环境中确实能省去不少重复的 try-catch 代码。想请教一下,文件上传部分如果要结合 multer,是否有推荐的目录结构或安全校验技巧?另外,安全配置方面除了常用的 helmet 和 cors,像速率限制(rate limiting)或者请求体大小限制这些,楼主一般会在什么阶段引入?
页:
[1]