[ PROMPT_NODE_23762 ]
中间件指南
[ SKILL_DOCUMENTATION ]
# 中间件指南 - Express 中间件模式
后端微服务中创建和使用中间件的完整指南。
## 目录
- [身份验证中间件](#身份验证中间件)
- [使用 AsyncLocalStorage 的审计中间件](#使用-asynclocalstorage-的审计中间件)
- [错误边界中间件](#错误边界中间件)
- [验证中间件](#验证中间件)
- [可组合中间件](#可组合中间件)
- [中间件顺序](#中间件顺序)
---
## 身份验证中间件
### SSOMiddleware 模式
**文件:** `/form/src/middleware/SSOMiddleware.ts`
typescript
export class SSOMiddlewareClient {
static verifyLoginStatus(req: Request, res: Response, next: NextFunction): void {
const token = req.cookies.refresh_token;
if (!token) {
return res.status(401).json({ error: 'Not authenticated' });
}
try {
const decoded = jwt.verify(token, config.tokens.jwt);
res.locals.claims = decoded;
res.locals.effectiveUserId = decoded.sub;
next();
} catch (error) {
res.status(401).json({ error: 'Invalid token' });
}
}
}
---
## 使用 AsyncLocalStorage 的审计中间件
### 来自 Blog API 的优秀模式
**文件:** `/form/src/middleware/auditMiddleware.ts`
typescript
import { AsyncLocalStorage } from 'async_hooks';
export interface AuditContext {
userId: string;
userName?: string;
impersonatedBy?: string;
sessionId?: string;
timestamp: Date;
requestId: string;
}
export const auditContextStorage = new AsyncLocalStorage();
export function auditMiddleware(req: Request, res: Response, next: NextFunction): void {
const context: AuditContext = {
userId: res.locals.effectiveUserId || 'anonymous',
userName: res.locals.claims?.preferred_username,
impersonatedBy: res.locals.isImpersonating ? res.locals.originalUserId : undefined,
timestamp: new Date(),
requestId: req.id || uuidv4(),
};
auditContextStorage.run(context, () => {
next();
});
}
// 获取当前上下文的 Getter
export function getAuditContext(): AuditContext | null {
return auditContextStorage.getStore() || null;
}
**优势:**
- 上下文贯穿整个请求生命周期
- 无需在每个函数间传递上下文
- 在服务和仓库中自动可用
- 类型安全的上下文访问
**在服务中的使用:**