name: express description: Express.js 中间件模式、路由、错误处理、安全性和生产环境最佳实践。 allowed-tools: Read, Write, Edit, Bash, Glob, Grep
Express 技能
使用 Express.js 构建 Node.js API 的专家级协助。
能力
- 使用中间件配置 Express 应用程序
- 实现 RESTful 路由模式
- 使用自定义中间件处理错误
- 应用安全最佳实践
- 设置验证和解析
- 配置生产环境部署
用法
当您需要时,请调用此技能:
- 使用 Express 构建 REST API
- 实现中间件管道
- 优雅地处理错误
- 添加身份验证/授权
- 设置 API 文档
输入
| 参数 | 类型 | 是否必需 | 描述 |
|---|---|---|---|
| routePath | 字符串 | 是 | 路由路径前缀 |
| methods | 数组 | 是 | HTTP 方法 |
| middleware | 数组 | 否 | 要应用的中间件 |
| validation | 布尔值 | 否 | 添加验证 |
模式
应用程序设置
// src/app.ts
import express, { Express, Request, Response, NextFunction } from 'express';
import cors from 'cors';
import helmet from 'helmet';
import compression from 'compression';
import morgan from 'morgan';
import { rateLimit } from 'express-rate-limit';
import { errorHandler, notFoundHandler } from './middleware/error';
import { usersRouter } from './routes/users';
import { authRouter } from './routes/auth';
export function createApp(): Express {
const app = express();
// 安全中间件
app.use(helmet());
app.use(cors({
origin: process.env.CORS_ORIGIN || 'http://localhost:3000',
credentials: true,
}));
// 速率限制
app.use(rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false,
}));
// 解析
app.use(express.json({ limit: '10kb' }));
app.use(express.urlencoded({ extended: true, limit: '10kb' }));
// 压缩和日志记录
app.use(compression());
app.use(morgan(process.env.NODE_ENV === 'production' ? 'combined' : 'dev'));
// 路由
app.use('/api/auth', authRouter);
app.use('/api/users', usersRouter);
// 健康检查
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
// 错误处理
app.use(notFoundHandler);
app.use(errorHandler);
return app;
}
带控制器的路由器
// src/routes/users.ts
import { Router } from 'express';
import { UsersController } from '../controllers/users.controller';
import { authenticate, authorize } from '../middleware/auth';
import { validate } from '../middleware/validate';
import { createUserSchema, updateUserSchema } from '../schemas/user.schema';
const router = Router();
const controller = new UsersController();
router.get('/', authenticate, controller.findAll);
router.get('/:id', authenticate, controller.findById);
router.post('/', authenticate, authorize('admin'), validate(createUserSchema), controller.create);
router.put('/:id', authenticate, validate(updateUserSchema), controller.update);
router.delete('/:id', authenticate, authorize('admin'), controller.delete);
export { router as usersRouter };
// src/controllers/users.controller.ts
import { Request, Response, NextFunction } from 'express';
import { UsersService } from '../services/users.service';
export class UsersController {
private service = new UsersService();
findAll = async (req: Request, res: Response, next: NextFunction) => {
try {
const { page = 1, limit = 10, search } = req.query;
const users = await this.service.findAll({
page: Number(page),
limit: Number(limit),
search: search as string,
});
res.json(users);
} catch (error) {
next(error);
}
};
findById = async (req: Request, res: Response, next: NextFunction) => {
try {
const user = await this.service.findById(req.params.id);
if (!user) {
return res.status(404).json({ error: '用户未找到' });
}
res.json(user);
} catch (error) {
next(error);
}
};
create = async (req: Request, res: Response, next: NextFunction) => {
try {
const user = await this.service.create(req.body);
res.status(201).json(user);
} catch (error) {
next(error);
}
};
update = async (req: Request, res: Response, next: NextFunction) => {
try {
const user = await this.service.update(req.params.id, req.body);
res.json(user);
} catch (error) {
next(error);
}
};
delete = async (req: Request, res: Response, next: NextFunction) => {
try {
await this.service.delete(req.params.id);
res.status(204).send();
} catch (error) {
next(error);
}
};
}
中间件模式
// src/middleware/auth.ts
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
export interface AuthRequest extends Request {
user?: {
id: string;
email: string;
role: string;
};
}
export function authenticate(req: AuthRequest, res: Response, next: NextFunction) {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({ error: '需要身份验证' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET!) as AuthRequest['user'];
req.user = decoded;
next();
} catch {
return res.status(401).json({ error: '无效令牌' });
}
}
export function authorize(...roles: string[]) {
return (req: AuthRequest, res: Response, next: NextFunction) => {
if (!req.user || !roles.includes(req.user.role)) {
return res.status(403).json({ error: '权限不足' });
}
next();
};
}
// src/middleware/validate.ts
import { Request, Response, NextFunction } from 'express';
import { ZodSchema, ZodError } from 'zod';
export function validate(schema: ZodSchema) {
return (req: Request, res: Response, next: NextFunction) => {
try {
schema.parse(req.body);
next();
} catch (error) {
if (error instanceof ZodError) {
return res.status(400).json({
error: '验证失败',
details: error.errors,
});
}
next(error);
}
};
}
// src/middleware/error.ts
import { Request, Response, NextFunction } from 'express';
export class AppError extends Error {
constructor(
public statusCode: number,
public message: string,
public isOperational = true
) {
super(message);
}
}
export function notFoundHandler(req: Request, res: Response) {
res.status(404).json({ error: '未找到' });
}
export function errorHandler(
err: Error,
req: Request,
res: Response,
next: NextFunction
) {
console.error(err);
if (err instanceof AppError) {
return res.status(err.statusCode).json({ error: err.message });
}
res.status(500).json({
error: process.env.NODE_ENV === 'production'
? '内部服务器错误'
: err.message,
});
}
异步处理程序包装器
// src/utils/asyncHandler.ts
import { Request, Response, NextFunction, RequestHandler } from 'express';
type AsyncRequestHandler = (
req: Request,
res: Response,
next: NextFunction
) => Promise<any>;
export function asyncHandler(fn: AsyncRequestHandler): RequestHandler {
return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
}
// 用法
router.get('/', asyncHandler(async (req, res) => {
const users = await usersService.findAll();
res.json(users);
}));
最佳实践
- 使用中间件处理横切关注点
- 实现适当的错误处理
- 验证所有输入
- 应用安全中间件(helmet、cors、速率限制)
- 使用控制器和服务结构化代码
目标流程
- nodejs-api-开发
- rest-api-开发
- mern-栈开发
- 后端架构