typescript 使用NestJS和class-validator创建Header自定义验证

fdbelqdn  于 2023-08-07  发布在  TypeScript
关注(0)|答案(2)|浏览(145)

我一直在使用class-validator验证请求,NestJS验证加上尝试验证头内容。
我的基本接口都在工作,但现在我正试图以同样的方式比较一些头字段数据。
我有一个关于自定义装饰器试图处理头部的问题,但是这个问题的解决方案将返回一个头部。我希望能够处理所有这些数据,类似于处理所有body()数据的方式。
我需要能够创建一个自定义的装饰提取头字段,并能够将它们传递到类验证器DTO。
例如,我想验证三个标题字段,例如:

User-Agent = 'Our Client Apps'
Content-Type = 'application/json'
traceabilityId = uuid

字符串
还有更多的领域,但如果我能让这个继续下去,那么我可以推断出其余的。我有一个简单的控制器示例:

@Controller(/rest/package)
export class PackageController {

    constructor(
        private PackageData_:PackageService
    )
    { }

    ...

    @Post('inquiry')
    @HttpCode(HttpStatus.OK)        // Not creating data, but need body, so return 200 OK
    async StatusInquiry(
        @RequestHeader() HeaderInfo:HeadersDTO,     // This should be the Headers validation using the decorator from the question above.


我正在尝试验证请求的头部是否包含一些特定的数据,并且我正在使用NestJS。我找到了这个information。虽然这是我想做的,而且看起来也很合适,但ClassType引用并不存在,我不确定该用什么来代替。
从这个例子来看,装饰者所指的是。
request-header.decorator.ts

export interface iError {
    statusCode:number;
    messages:string[];
    error:string;
}

export const RequestHeader = createParamDecorator(
async (value:  any, ctx: ExecutionContext) => {

    // extract headers
    const headers = ctx.switchToHttp().getRequest().headers;

    // Convert headers to DTO object
    const dto = plainToClass(value, headers, { excludeExtraneousValues: true });

    // Validate
    const errors: ValidationError[] = await validate(dto);

    if (errors.length > 0) {
        let ErrorInfo:IError = {
            statusCode: HttpStatus.BAD_REQUEST,
            error: 'Bad Request',
            message: new Array<string>()
        };
        
        errors.map(obj => { 
            AllErrors = Object.values(obj.constraints);    
            AllErrors.forEach( (OneError) => {
            OneError.forEach( (Key) => {
                ErrorInfo.message.push(Key);
            });
        });

        // Your example, but wanted to return closer to how the body looks, for common error parsing
        //Get the errors and push to custom array
        // let validationErrors = errors.map(obj => Object.values(obj.constraints));
        throw new HttpException(`${ErrorInfo}`, HttpStatus.BAD_REQUEST);
    }

    // return header dto object
    return dto;
},


我在将约束Map到字符串数组时遇到了问题。
我的标题DTO.ts:

import { Expose } from 'class-transformer';
import { Equals, IsIn, IsString } from 'class-validator';
export class HeadersDTO {

    @IsString()
    @Equals('OurApp')
    @Expose({ name: 'user-agent' })
    public readonly 'user-agent':string;

    @IsString() 
    @IsIn(['PRODUCTION', 'TEST'])
    public readonly operationMode:string;
}


通过Postman为请求发送的标头:

Content-Type:application/json
operationMode:PRODUCTION
Accept-Language:en

g6ll5ycj

g6ll5ycj1#

我刚刚测试了下面的代码,这是工作。我觉得你缺少合适的类型,

async StatusInquiry(
    @RequestHeader() HeaderInfo:HeadersDTO,

字符串
RequestHeaderDecorator this @RequestHeader(HeadersDTO) HeaderInfo:HeadersDTO,中应该有HeadersDTO作为参数传入
然后我创建了customDecorator.ts,就像这样,

export const RequestHeader = createParamDecorator(
//Removed ClassType<unknown>,, I don't think you need this here
async (value:  any, ctx: ExecutionContext) => {

    // extract headers
    const headers = ctx.switchToHttp().getRequest().headers;

    // Convert headers to DTO object
    const dto = plainToClass(value, headers, { excludeExtraneousValues: true });

    // Validate
    const errors: ValidationError[] = await validate(dto);
    
    if (errors.length > 0) {
        //Get the errors and push to custom array
        let validationErrors = errors.map(obj => Object.values(obj.constraints));
        throw new HttpException(`Validation failed with following Errors: ${validationErrors}`, HttpStatus.BAD_REQUEST);
    }

    // return header dto object
    return dto;
},


);
我的HeadersDTO.ts文件

export class HeadersDTO 
{
  @IsDefined()
  @Expose({ name: 'custom-header' })
  "custom-header": string; // note the param here is in double quotes
}


当我看编译的TS文件时,我发现这个的原因,它看起来像这样,

class HeadersDTO {
}
tslib_1.__decorate([
    class_validator_1.IsDefined(),
    class_transformer_1.Expose({ name: 'custom-header' }),
    tslib_1.__metadata("design:type", String)
], HeadersDTO.prototype, "custom-header", void 0);
exports.HeadersDTO = HeadersDTO;


我得到以下错误时,我不通过头部,

[
  ValidationError {
    target: HeadersDTO { 'custom-header': undefined },
    value: undefined,
    property: 'custom-header',
    children: [],
    constraints: { isDefined: 'custom-header should not be null or undefined' }
  }
]

d7v8vwbk

d7v8vwbk2#

issue you referenced中所述,您需要创建一个DTO类并将其传递给RequestHeader装饰器。
例如

export class MyHeaderDTO {
    @IsString()
    @IsDefined()
    @Expose({ name: 'myheader1' })        // required as headers are case insensitive
    myHeader1: string;
}

...

@Get('/hello')
getHello(@RequestHeader(MyHeaderDTO) headers: MyHeaderDTO) {
    console.log(headers);
}

字符串

相关问题