
使用 Node.js 和 Express 构建 REST API:2026 完整指南
Node.js + Express 仍然是构建 REST API 最流行的后端技术栈。2026 年,随着 Express 5 稳定版发布和生态系统的成熟,以下是构建快速、可维护且生产就绪 API 的权威指南。
项目设置
mkdir my-api && cd my-api
npm init -y
npm install express
npm install --save-dev typescript @types/express @types/node ts-node nodemon
npx tsc --init
目录结构:
src/
routes/
users.ts
products.ts
controllers/
userController.ts
middleware/
auth.ts
errorHandler.ts
models/
User.ts
app.ts
server.ts
Express 应用
// src/app.ts
import express, { Application } from 'express';
import userRoutes from './routes/users';
import { errorHandler } from './middleware/errorHandler';
import { notFound } from './middleware/notFound';
const app: Application = express();
// 内置中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// 路由
app.use('/api/users', userRoutes);
// 404 处理(必须在路由之后)
app.use(notFound);
// 错误处理(必须在最后)
app.use(errorHandler);
export default app;
// src/server.ts
import app from './app';
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
RESTful 路由
// src/routes/users.ts
import { Router } from 'express';
import {
getUsers,
getUserById,
createUser,
updateUser,
deleteUser,
} from '../controllers/userController';
import { authenticate } from '../middleware/auth';
import { validateUser } from '../middleware/validate';
const router = Router();
router.get('/', authenticate, getUsers);
router.get('/:id', authenticate, getUserById);
router.post('/', validateUser, createUser);
router.put('/:id', authenticate, validateUser, updateUser);
router.delete('/:id', authenticate, deleteUser);
export default router;
控制器
// src/controllers/userController.ts
import { Request, Response, NextFunction } from 'express';
import { UserService } from '../services/userService';
const userService = new UserService();
export async function getUsers(req: Request, res: Response, next: NextFunction) {
try {
const { page = 1, limit = 20 } = req.query;
const users = await userService.findAll({
page: Number(page),
limit: Number(limit),
});
res.json({
success: true,
data: users,
meta: { page: Number(page), limit: Number(limit) },
});
} catch (error) {
next(error); // 传递给错误处理
}
}
export async function getUserById(req: Request, res: Response, next: NextFunction) {
try {
const user = await userService.findById(req.params.id);
if (!user) {
return res.status(404).json({ success: false, message: 'User not found' });
}
res.json({ success: true, data: user });
} catch (error) {
next(error);
}
}
export async function createUser(req: Request, res: Response, next: NextFunction) {
try {
const user = await userService.create(req.body);
res.status(201).json({ success: true, data: user });
} catch (error) {
next(error);
}
}
中间件
认证中间件
// src/middleware/auth.ts
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
interface JwtPayload {
userId: string;
email: string;
}
// 扩展 Request 类型
declare global {
namespace Express {
interface Request {
user?: JwtPayload;
}
}
}
export function authenticate(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization?.split(' ')[1]; // Bearer TOKEN
if (!token) {
return res.status(401).json({ success: false, message: 'No token provided' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET!) as JwtPayload;
req.user = decoded;
next();
} catch {
res.status(401).json({ success: false, message: 'Invalid token' });
}
}
验证中间件(使用 Zod)
// src/middleware/validate.ts
import { z } from 'zod';
import { Request, Response, NextFunction } from 'express';
const userSchema = z.object({
name: z.string().min(2).max(50),
email: z.string().email(),
password: z.string().min(8),
role: z.enum(['user', 'admin']).optional().default('user'),
});
export function validateUser(req: Request, res: Response, next: NextFunction) {
const result = userSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({
success: false,
message: 'Validation failed',
errors: result.error.flatten().fieldErrors,
});
}
req.body = result.data; // 使用解析/强制转换后的数据
next();
}
全局错误处理
// src/middleware/errorHandler.ts
import { Request, Response, NextFunction } from 'express';
export class AppError extends Error {
constructor(
public message: string,
public statusCode: number = 500,
public isOperational: boolean = true
) {
super(message);
Object.setPrototypeOf(this, AppError.prototype);
}
}
export function errorHandler(
err: Error,
req: Request,
res: Response,
next: NextFunction
) {
if (err instanceof AppError) {
return res.status(err.statusCode).json({
success: false,
message: err.message,
});
}
// 意外错误——在生产环境中记录并隐藏细节
console.error(err);
res.status(500).json({
success: false,
message: process.env.NODE_ENV === 'production'
? 'Internal server error'
: err.message,
});
}
REST API 最佳实践
使用一致的响应格式
// 成功
{ "success": true, "data": { ... }, "meta": { "page": 1, "total": 100 } }
// 错误
{ "success": false, "message": "User not found", "errors": { "email": ["Invalid format"] } }
HTTP 状态码
| 场景 | 状态码 |
|---|---|
| 成功 (GET) | 200 OK |
| 已创建 (POST) | 201 Created |
| 无内容 (DELETE) | 204 No Content |
| 错误请求 | 400 Bad Request |
| 未授权 | 401 Unauthorized |
| 禁止 | 403 Forbidden |
| 未找到 | 404 Not Found |
| 验证错误 | 422 Unprocessable Entity |
| 服务器错误 | 500 Internal Server Error |
分页模式
// GET /api/users?page=2&limit=20&sort=createdAt&order=desc
router.get('/', async (req, res) => {
const { page = 1, limit = 20, sort = 'createdAt', order = 'desc' } = req.query;
const skip = (Number(page) - 1) * Number(limit);
const [users, total] = await Promise.all([
User.find().sort({ [sort as string]: order as 'asc' | 'desc' }).skip(skip).limit(Number(limit)),
User.countDocuments()
]);
res.json({
success: true,
data: users,
meta: {
page: Number(page),
limit: Number(limit),
total,
totalPages: Math.ceil(total / Number(limit))
}
});
});
速率限制与安全
npm install express-rate-limit helmet cors
import rateLimit from 'express-rate-limit';
import helmet from 'helmet';
import cors from 'cors';
// 安全头
app.use(helmet());
// CORS
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') || 'http://localhost:3000',
credentials: true,
}));
// 速率限制:每 15 分钟 100 次请求
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false,
message: { success: false, message: 'Too many requests, please try again later.' },
});
app.use('/api/', limiter);
环境变量
# .env
PORT=3000
NODE_ENV=development
JWT_SECRET=your-super-secret-key-here
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
ALLOWED_ORIGINS=http://localhost:5173,https://myapp.com
// 使用 dotenv 加载
import dotenv from 'dotenv';
dotenv.config(); // 必须在访问 process.env 之前调用
测试你的 API
# 使用 curl 快速测试
curl -X GET http://localhost:3000/api/users
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{"name":"John","email":"john@example.com","password":"secret123"}'
# 带认证令牌
curl -X GET http://localhost:3000/api/users \
-H "Authorization: Bearer eyJhbGci..."
总结
生产级 Node.js API 的关键要点:
- 分离关注点:路由 → 控制器 → 服务 → 模型
- 始终使用中间件 处理认证、验证和错误
- 全局错误处理 捕获所有异常——不要让错误溜走
- 验证所有输入,使用 Zod 或 Joi 进行处理前验证
- 使用环境变量——永远不要硬编码密钥
- 添加速率限制和安全头,在上线前完成
- 一致的响应格式 使客户端代码更简单
→ 使用 JSON Viewer 测试你的 API 响应,使用 JWT Parser 解析 JWT。