NestJS 自定义装饰器返回未定义

Posted

技术标签:

【中文标题】NestJS 自定义装饰器返回未定义【英文标题】:NestJS custom decorator returns undefined 【发布时间】:2020-06-30 09:20:24 【问题描述】:

早上好,

我正在尝试创建自定义装饰器: user.decorator.ts

import  createParamDecorator, ExecutionContext  from '@nestjs/common';

export const User = createParamDecorator(
  (data: string, ctx: ExecutionContext) => 
    const request = ctx.switchToHttp().getRequest();
    const user = request.user;

    return data ? user && user[data] : user;
  ,
);

user.entity.ts

import  Entity, PrimaryGeneratedColumn, Column, BeforeInsert  from "typeorm";
import * as bcrypt from 'bcryptjs';
import * as jwt from 'jsonwebtoken';
import  UserRO  from "./user.dto";

@Entity("user")
export class UserEntity 

    @PrimaryGeneratedColumn('uuid')
    id: string;

    @Column(
        type: 'varchar',
        length: 50,
        unique: true,
    )
    username: string;

    @Column('text')
    password: string;

    @Column('text')
    role: string;

    (...)


最后,user.controller.ts(只有有用的部分):

(...)
    @Post('login')
    @UsePipes(new ValidationPipe())
    login(@Body() data: UserDTO,  @User('role') role: string) 
        console.log(`hello $role`);
        return this.userService.login(data);
(...)
    

我的问题:console.log(...) 返回我hello undefined,而预期的响应应该是hello admin(因为管理员是数据库中用户的角色)

编辑:我也尝试在我的装饰器中 console.log(user) 并且它也未定义。

EDIT2:我的 HttpErrorFilter 还说:Cannot read property 'role' of undefined

我密切关注文档,但无法确定问题出在哪里 (https://docs.nestjs.com/custom-decorators)。

感谢您的宝贵时间。

【问题讨论】:

【参考方案1】:

我也对此感到困惑。我升级到 NestJS 7,并按照 migration guide 尝试更新我的用户装饰器。

我无法工作的部分是const request = ctx.switchToHttp().getRequest();。出于某种原因,getRequest() 返回未定义。

对我有用的是:

import  createParamDecorator, ExecutionContext  from '@nestjs/common';

export const CurrentUser = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => 
    return ctx.getArgByIndex(2).req.user;
  
);

execution context 文档建议不要使用getArgByIndex(),所以我确定我做错了一些简单的事情。对其他答案和 cmets 会说什么感兴趣。

【讨论】:

【参考方案2】:

我找到了解决办法。

user.decorator.ts:

const user = request.user; 更改为const user = request.body;

根据nestjs 的文档,它应该是.user,但是当我更深入地查看请求时,我注意到信息中没有“用户”而是“正文”。 (https://docs.nestjs.com/custom-decorators)

不知道是我之前搞砸了还是文档已经过时了。

问题解决了!

编辑:第二个解决方案:

我忘记在顶部使用@UseGuards(new AuthGuard()),而request.user 是使用AuthGuard 创建的..

【讨论】:

【参考方案3】:

我对这个空/未定义的请求很生气。因为文档中的信息 (custom-decorators) 对我不起作用。我正在使用graphql + typescript。那么神奇的解决方案是这样的:

export const CurrentUser = createParamDecorator(
    (data: unknown, context: ExecutionContext) => 
        const ctx = GqlExecutionContext.create(context);
        return ctx.getContext().req.user;
    ,
);

【讨论】:

【参考方案4】:

如果您对 HTTP(REST) 和 graphql 使用相同的装饰器

if (ctx.getType() == 'http') 
  return ctx.switchToHttp().getRequest().user;
 else 
  const gqlContext = GqlExecutionContext.create(ctx);
  return gqlContext.getContext().user;

【讨论】:

以上是关于NestJS 自定义装饰器返回未定义的主要内容,如果未能解决你的问题,请参考以下文章

NestJS 的自定义路由装饰器

使用自定义 TS 装饰器的组件方法中未定义角服务

Django - 自定义装饰器 - 参数未填充

打字稿方法返回未定义的方法装饰器

Django 自定义装饰器 - 函数没有属性 get

通过库共享时未注册 NestJS 自定义 PassportStrategy