96SEO 2026-08-13 02:42 0
刚开始写 NestJS 时我也把 Guard、Interceptor、Middleware 当成几种差不多的“前置钩子”:反正都能拿到 Request,代码放在哪里似乎都能跑。项目变大之后这种做法很快就会失控。认证藏在拦截器里参数转换散落在 Controller。日志中间件又不知道接口上的元数据,最终每一层都在做别人的工作。

真正好用的判断方式不是背定义,而是先回答三个问题:这段逻辑发生在请求的哪个阶段?它是否依赖具体 Handler 的元数据?它只关心输入,还是需要同时观察返回值和异常?
下面这张图足够覆盖大多数 HTTP 应用的主流程:
flowchart LR
A --> B
B --> C
C --> D
D --> E
E --> F
F --> G
G --> H
B -. 未捕获异常 .-> X
C -. 未捕获异常 .-> X
D -. 未捕获异常 .-> X
E -. 未捕获异常 .-> X
F -. 未捕获异常 .-> X
Middleware 最早进入,随后 Guard 判断请求能否继续。Interceptor 的前置逻辑包住 Pipe 和 Handler,Handler 返回后再的异常最终交给 Exception Filter。
同一种组件还可能注册在全局、Controller 和方法三个作用域。范围越大,越应该只承载稳定、通用的规则。话说回来,要特别注意 Interceptor 是洋葱模型:进入时按全局到局部执行。返回时顺序相反,其实,假设注册顺序是性能统计、慢请求监控、限流、响应包装。响应会先被最内层包装,再逐层返回。顺序不是形式问题,它会直接影响计时范围、缓存内容和错误处理。
注册方式也表达了设计意图。认证基线可以用 APP_GUARD
注册为全局 Provider。操作审计可用 APP_INTERCEPTOR
覆盖全局,参数基线通常由 app.useGlobalPipes
建立;只服务于单个业务域的能力则用 @UseGuards
@UseInterceptors
放到 Controller 或方法上。通过 Provider 注册的全局组件可以正常注入依赖,比在启动文件里直接 new
一个实例更容易测试和维护。方法级配置最精确,但若几十个接口都在重复同一行装饰器。就应重新判断它是否已经是 Controller 或全局规则。
自定义装饰器最常见的误解,是把它当成一段隐藏的业务逻辑。实际项目里 我更愿意把它限制为两类。
第一类是参数装饰器,从执行上下文中取出前面环节已经准备好的数据: *
export const CurrentUser = createParamDecorator(
=> {
const request = context.switchToHttp.getRequest;return request.user;},),@Get
profile user: UserContext) {}
它消除了 @Req 和 Request 字段名在 Controller 中的重复,也让参数意图更明确。但 @CurrentUser 不应该自己解析 Token;request.user 应由认证 Guard 提前写入。类似做法还适合当前租户、 操作者、 角色、 数据范围和标准化日期等上下文。*
第二类是元数据装饰器,
为 Guard 或 Interceptor 留下声明: *
export const Public = => SetMetadata;
其实,export const RequirePermission = =>
SetMetadata;说起来,export const LogOperation = =>
SetMetadata;
这些函数本身既不认证。
也不查权限,
更不写日志。
它们只把规则贴在类或方法上,真正的执行者通过 Reflector
读取。怎么说呢,
装饰器和使用者应该成对设计:
@Public 对应认证 Guard。
@RequirePermission 对应权限 Guard,
@LogOperation 对应操作日志 Interceptor。按理说,
只有装饰器而没有使用者。声明不会产生任何效果,*
当一组声明总是一起出现,
可以用 applyDecorators
组合。例如把权限、
操作日志和 API
文档组合成一个业务动作装饰器。怎么说呢,但组合装饰器仍应保持可推断:
看到名称就能知道它声明了什么。不能把数据库查询或外部调用藏进去。
元数据 Key 最好集中定义为常量或 Symbol,
并明确方法级配置是覆盖还是合并类级配置;其实,
getAllAndOverride
和 getAllAndMerge
的选择应该由这条语义决定。
而不是随手使用。*
Middleware运行在 Nest 路由处理链之前,适合处理协议和入口层问题. 例如某组路由第一段方法必须是支持的网站类型:
@Injectable export class PlatformMiddleware implements NestMiddleware { use { if ) { throw new BadRequestException;} next,} } configure { consumer .apply .forRoutes;}
Guard职责很直接: 返回 true 放行,否则抛出异常或返回 false . 认证授权都属于这个阶段,但两者不要混为一谈.
生产服务更稳妥默认值全局保护。只对少量公开接口显式放行 :
@Public @Post login {}
Global Auth Guard读取方法与类上元数据,并在认证成功后准备使用者上下文 :
const isPublic = this.reflector.getAllAndOverride ( IS_PUBLIC_KEY,);ifreturn true;const request=context.switchToHttp.getRequest;const token=this.extractToken;if throw new UnauthorizedException;request.user=await this.tokenService.verify;return true,
接口负责声明需要权限 :
。授权读取声明结合 Auth 写入信息判断 : ( PERMISSION_KEY,);ifreturn true;const request=context.switchToHttp.getRequest;if throw new UnauthorizedException;const allowed=await this.permissionService.hasAny( request.user.id,required );不过,if throw new ForbiddenException;return true,
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback