Express.js 完整指南:2026 年用 Node.js 构建 REST API
从零开始掌握 Express.js。本教程涵盖路由、中间件、REST API 设计、JWT 认证、错误处理,以及 Express 与 Fastify、Koa、Hapi 的对比。
Express.js 是用于构建 REST API 和 Web 应用的最小化 Node.js Web 框架。通过 npm install express 安装,用 app.get/post/put/delete 定义路由,用 app.use() 使用中间件,用四参数中间件处理错误,并使用 JWT + bcrypt 保护 API。Express 在 2026 年仍是最流行的 Node.js 框架,每周下载量超过 3000 万次。
什么是 Express.js?
Express.js 是一个快速、极简、非约束性的 Node.js Web 框架。由 TJ Holowaychuk 于 2010 年发布,现由 OpenJS 基金会维护。Express 已成为 Node.js 生态系统中构建 HTTP 服务器和 REST API 的事实标准。
该框架的设计哲学是极简主义:它只提供核心工具——路由、中间件支持和 HTTP 请求/响应工具,不强制要求任何特定的项目结构、模板引擎或数据库层。这种灵活性是 Express 最大的优势,也是它在 2026 年面对众多新框架竞争时仍保持相关性的原因。
- Express.js 是 Node.js
http模块之上的薄层,提供路由和中间件。 - 中间件函数是构建模块——通过
next()按顺序处理请求。 - 使用
express.Router()模块化路由,保持代码有序。 - 始终将集中式错误处理中间件(4个参数)作为最后一个
app.use()调用添加。 - 使用 helmet、cors、express-rate-limit 和基于 JWT 的认证保护生产应用。
- Fastify 比 Express 快 2–3 倍,但 Express 在生态系统规模和社区知识方面占优。
快速入门:安装与首个服务器
# 初始化新的 Node.js 项目
mkdir my-api && cd my-api
npm init -y
# 安装 Express
npm install express
# 安装 TypeScript 类型(可选但推荐)
npm install --save-dev @types/express typescript ts-node// index.js — 最简 Express 服务器
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.json());
app.get('/', (req, res) => {
res.json({ message: 'Express 服务器运行正常!' });
});
app.listen(PORT, () => {
console.log('服务器运行在 http://localhost:' + PORT);
});路由:GET、POST、PUT、DELETE
const express = require('express');
const router = express.Router();
// GET — 获取资源列表
router.get('/', (req, res) => {
const { page = '1', limit = '20' } = req.query;
res.json({ data: [], page: parseInt(page, 10), limit: parseInt(limit, 10) });
});
// POST — 创建资源
router.post('/', (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: '缺少必填字段' });
}
res.status(201).json({ id: 1, name, email });
});
// GET /:id — 获取单个资源
router.get('/:id', (req, res) => {
res.json({ id: req.params.id });
});
// PUT /:id — 完整替换资源
router.put('/:id', (req, res) => {
res.json({ id: req.params.id, ...req.body });
});
// DELETE /:id — 删除资源
router.delete('/:id', (req, res) => {
res.status(204).send();
});
module.exports = router;中间件
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const morgan = require('morgan');
const rateLimit = require('express-rate-limit');
const app = express();
// 安全头
app.use(helmet());
// 跨域资源共享
app.use(cors({ origin: ['https://myapp.com'], credentials: true }));
// 请求日志
app.use(morgan('combined'));
// 请求体解析
app.use(express.json({ limit: '10mb' }));
// 速率限制
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 分钟
max: 100,
message: { error: '请求过于频繁,请稍后再试' },
});
app.use('/api/', limiter);JWT 认证
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
// 注册:哈希密码
const hash = await bcrypt.hash(password, 12);
// 登录:验证并颁发 JWT
const match = await bcrypt.compare(password, user.passwordHash);
if (!match) return res.status(401).json({ error: '凭据无效' });
const token = jwt.sign(
{ sub: user.id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '15m' }
);
res.json({ accessToken: token });
// 认证中间件
function authenticate(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
return res.status(401).json({ error: '缺少认证令牌' });
}
try {
req.user = jwt.verify(authHeader.slice(7), process.env.JWT_SECRET);
next();
} catch (err) {
res.status(401).json({ error: err.name === 'TokenExpiredError' ? '令牌已过期' : '令牌无效' });
}
}错误处理
// 集中式错误处理中间件(必须是最后一个 app.use)
function errorHandler(err, req, res, next) {
console.error(err.message);
if (err.isOperational) {
return res.status(err.statusCode).json({ error: err.message, code: err.code });
}
res.status(500).json({
error: process.env.NODE_ENV === 'development' ? err.message : '服务器内部错误',
});
}
// async 错误处理包装器
function asyncHandler(fn) {
return (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next);
}
// 使用示例
app.get('/users/:id', asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
if (!user) throw new AppError('用户不存在', 404, 'NOT_FOUND');
res.json({ data: user });
}));
app.use(errorHandler); // 必须最后注册常见问题
Express.js 在 2026 年还值得学习吗?
当然值得。Express 每周下载量超过 3000 万次,是 Node.js 生态中最广泛使用的框架。大量工作机会、教程和中间件都基于 Express。即使你最终使用 NestJS 或 Fastify,理解 Express 的中间件模式也至关重要,因为这些框架都建立在相同概念之上。
Express 和 Fastify 哪个更好?
Fastify 在基准测试中比 Express 快 2–3 倍,内置 JSON Schema 验证和更快的序列化。但对大多数应用来说,瓶颈在数据库而非框架。Express 生态系统更大,学习资源更丰富。建议:默认选 Express,当吞吐量成为实测瓶颈时再考虑 Fastify。
如何处理 Express 中的异步错误?
Express 4 不会自动捕获未处理的 Promise 拒绝。使用以下三种方案之一:在 try/catch 中调用 next(err);使用 asyncHandler 包装函数;或安装 express-async-errors 包。Express 5 原生支持 async/await 错误传播,无需额外处理。