NestJS 中间件使用场景
日志记录、JWT 认证、速率限制
日志记录
支持环境区分、JSON 格式输出、忽略健康检查接口
ts
// src/middlewares/logger.middleware.ts
import { Injectable, NestMiddleware, Logger } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
private readonly logger = new Logger('HTTP');
private readonly isProd: boolean;
constructor(private readonly configService: ConfigService) {
this.isProd = this.configService.get('NODE_ENV') === 'production';
}
use(req: Request, res: Response, next: NextFunction) {
// 忽略健康检查接口
if (req.originalUrl === '/health') {
next();
return;
}
const { method, originalUrl, ip } = req;
const userAgent = req.get('user-agent') || '';
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
const statusCode = res.statusCode;
// 生产环境输出 JSON 格式,开发环境输出简易格式
if (this.isProd) {
this.logger.log(
JSON.stringify({
timestamp: new Date().toISOString(),
method,
url: originalUrl,
statusCode,
duration,
ip,
userAgent,
})
);
} else {
this.logger.log(
`${method} ${originalUrl} ${statusCode} ${duration}ms - ${ip} ${userAgent}`
);
}
});
next();
}
}JWT 认证
结合 jsonwebtoken 实现接口认证
ts
// src/middlewares/jwt-auth.middleware.ts
import { Injectable, NestMiddleware, UnauthorizedException } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import * as jwt from 'jsonwebtoken';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class JwtAuthMiddleware implements NestMiddleware {
private readonly secret: string;
constructor(private readonly configService: ConfigService) {
this.secret = this.configService.get('JWT_SECRET');
}
use(req: Request, res: Response, next: NextFunction) {
try {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
throw new UnauthorizedException('Invalid authorization header');
}
const token = authHeader.split(' ')[1];
const payload = jwt.verify(token, this.secret);
req.user = payload; // 挂载用户信息到 req
next();
} catch (error) {
throw new UnauthorizedException('Invalid or expired token');
}
}
}速率限制
基于 rate-limiter-flexible 实现接口限流
ts
// src/middlewares/rate-limit.middleware.ts
import { Injectable, NestMiddleware, TooManyRequestsException } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { RateLimiterMemory } from 'rate-limiter-flexible';
@Injectable()
export class RateLimitMiddleware implements NestMiddleware {
private readonly limiter = new RateLimiterMemory({
points: 10, // 10 次请求
duration: 60, // 60 秒
});
async use(req: Request, res: Response, next: NextFunction) {
const ip = req.ip;
try {
// 校验限流
await this.limiter.consume(ip);
next();
} catch (error) {
throw new TooManyRequestsException('Too many requests, please try again later');
}
}
}