第九章 Nest 自定义装饰器

本章将学习如何自定义装饰器 以及如何将多个装饰器合并成一个

首先先创建一个项目:

nest new custom-decorator -p npm

1717899449486.png
接着我们创建一个装饰器:

nest g decorator test --flat

1717899681593.png
1717900784497.png
我们创建一个Guard 用于使用 reflector 来取 metadata:

nest g guard test --flat --no-spec

1717901129768.png
修改test.guard.ts 里的代码:

import { CanActivate, ExecutionContext, Inject, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';

@Injectable()
export class TestGuard implements CanActivate {

  @Inject(Reflector)
  private reflector: Reflector;
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {

    console.log(this.reflector.get('test', context.getHandler()));


    return true;
  }
}

作用是打印 this.reflector.get(‘test’, context.getHandler())
接着在Controller 里进行使用

import { Controller, Get, SetMetadata, UseGuards } from '@nestjs/common';
import { AppService } from './app.service';
import { TestGuard } from './test.guard';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) { }

  @Get()
  @SetMetadata('test', 'admin')
  @UseGuards(TestGuard)
  getHello(): string {
    return this.appService.getHello();
  }
}

1717901544089.png
启动服务:

npm run start:dev

访问 http://localhost:3000 可以看到打印的 metadata
1717901772833.png
不同 metadata 有不同的业务场景:

  1. 身份验证和授权:可以使用metadata来标记需要身份验证或授权的路由和方法,然后根据标记的信息进行相应的操作,例如检查用户的权限和角色信息。
  2. 表单验证:可以使用metadata来标记需要验证的表单字段,然后根据标记的信息进行相应的验证操作,例如检查字段的类型、长度、格式等。
  3. 日志记录:可以使用metadata来标记需要记录日志的方法和路由,然后根据标记的信息进行日志的记录,例如记录方法的调用时间、参数和返回值。
  4. 缓存管理:可以使用metadata来标记需要缓存的方法和路由,然后根据标记的信息进行缓存的管理,例如设置缓存的过期时间和清除缓存的策略。
  5. 路由拦截和转发:可以使用metadata来标记需要进行路由拦截和转发的方法和路由,然后根据标记的信息进行相应的操作,例如拦截路由请求进行权限校验或者转发路由请求到其他服务。

但是 直接使用@SetMetadata 来设置太原始了,所以可以使用之前创建的装饰器 封装一层。
1717902048515.png
修改 app.controller.ts 新增getTest函数 使用 自定义的Test装饰器

import { Controller, Get, SetMetadata, UseGuards } from '@nestjs/common';
import { AppService } from './app.service';
import { TestGuard } from './test.guard';
import { Test } from './test.decorator';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) { }

  @Get()
  @SetMetadata('test', 'admin')
  @UseGuards(TestGuard)
  getHello(): string {
    return this.appService.getHello();
  }

  @Get('test')
  @Test('admin')
  @UseGuards(TestGuard)
  getTest(): string {
    return this.appService.getHello();
  }
}

访问 http://localhost:3000/test可以看到打印的 metadata
1717902328812.png

我们也可以将多给装饰器 合成一个使用

创建一个装饰器 demo

nest g decorator demo --flat

1717902625449.png
修改装饰器代码如下:

import { Get, SetMetadata, UseGuards, applyDecorators } from '@nestjs/common';
import { Test } from './test.decorator';
import { TestGuard } from './test.guard';

export const Demo = (path, role) => {
    return applyDecorators(
        Get(path),
        Test(role),
        UseGuards(TestGuard)
    )
}

1717902831522.png
在Controller 里新增加test2接口

@Demo('test2', 'admin')
  getTest2(): string {
    return this.appService.getHello();
  }

1717902969891.png
访问 http://localhost:3000/test2 可以看到功能也能正常使用
1717903020762.png
此时 三个接口的装饰器实现的效果都是一样的
除了接口层面 我们也可以自定义参数装饰器:
再次创建一个装饰器:

nest g decorator param  --flat

1717903386402.png
修改 param.decorator.ts 代码如下

import { ExecutionContext, SetMetadata, createParamDecorator } from '@nestjs/common';

export const Param =createParamDecorator(
    (data:string,ctx:ExecutionContext)=>{
        return 'param'
    }
)

在app.controller.ts 中 新增接口test3 使用上面定义的 @Param() 装饰器

@Get('test3')
  getTest3(@Param() param): string {
    return 'param';
  }

1717903683632.png
访问 http://localhost:3000/test3 可以看到就是装饰器 Param的返回值
1717903768199.png
1717903817614.png
createParamDecorator 的回调函数可以接收以下参数:

  1. data:表示由装饰器传递的数据。这个参数是可选的。
  2. ctx:表示当前请求的上下文对象,可以通过 @Req() 装饰器获取。

通过这个函数 我们自己也可以实现 内置的@Param、@Query、@Ip、@Headers 等装饰器
我们来尝试一下,实现一个获取请求头信息的装饰器
创建装饰器:

nest g decorator myHeaders  --flat

1717904147950.png
修改 my-headers.decorator.ts 代码如下:

import { ExecutionContext, SetMetadata, createParamDecorator } from '@nestjs/common';
/**
 * 创建一个参数装饰器,用于获取HTTP请求的头部信息。
 * 
 * @param key 需要获取的头部信息的键。如果提供,则只返回对应键的头部信息;如果不提供,则返回所有头部信息。
 * @param ctx 操作的上下文环境,用于切换到HTTP上下文并获取请求对象。
 * @returns 如果提供了键,则返回对应键的头部信息;否则返回所有头部信息。
 */
export const MyHeaders = createParamDecorator(
    (key: string, ctx: ExecutionContext) => {
        // 切换到HTTP上下文并获取请求对象
        const request: Request = ctx.switchToHttp().getRequest();
        // 根据是否提供了键来返回对应的头部信息或所有头部信息
        return key ? request.headers[key.toLowerCase()] : request.headers;
    },
);

这个函数创建了一个参数装饰器MyHeaders,用于在NestJS中获取HTTP请求的头部信息。使用createParamDecorator函数创建装饰器,并接收一个键key和上下文环境ctx作为参数。在装饰器函数内部,通过ctx.switchToHttp().getRequest()切换到HTTP上下文并获取请求对象。然后根据是否提供了键key来返回对应的头部信息或所有头部信息。如果提供了键,则返回对应键的头部信息;否则返回所有头部信息。
修改 app.controller.ts 新增接口:

@Get('test4')
  getTest4(@MyHeaders('Accept') headers1, @MyHeaders('Accept') headers2): string {
    console.log('headers1', headers1);
    console.log('headers2', headers2);
    return 'param';
  }

1717904505688.png
访问 http://localhost:3000/test4 可以看到控制台返回了请求头的 Accept信息
1717904571795.png

  • 20
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫ゞ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值