初始化和传递请求上下文的最佳实践是什么 [英] NestJS what is the best practice to initialise and pass request context

查看:14
本文介绍了初始化和传递请求上下文的最佳实践是什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个全局拦截器,它需要初始化我自己的请求上下文DTO,并且我希望此DTO可以在处理当前请求的控制器中访问。

到目前为止,我找到的解决方案是创建请求范围的可注入RequestContext类:

import {
    Injectable,
    Scope
} from '@nestjs/common';
import { Request } from 'express';
import { IncomingHttpHeaders } from 'http';

@Injectable({ scope: Scope.REQUEST })
export class RequestContext {
    public headers: IncomingHttpHeaders;
    ....

    initialize(request: Request) {
        this.headers = request.headers;
        .....
    }
}

并将此类注入拦截器:

import {
    NestInterceptor,
    ExecutionContext,
    CallHandler,
    Injectable,
    Inject
} from '@nestjs/common';
import { Request } from 'express';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { RequestContext } from '../dto';

@Injectable()
export class RequestContextInterceptor implements NestInterceptor {
    constructor(
        @Inject(RequestContext)
        protected requestContext: RequestContext
    ) { }

    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        const request = context.switchToHttp().getRequest<Request>();
        this.requestContext.initialize(request);

        return next.handle()
            .pipe(
                tap(() => {
                    // decorate response
                }));
    }
}

然后将此RequestContext注入每个控制器.

import {
    Controller,
    UseInterceptors,
    Inject,
    Get
} from '@nestjs/common';
import { BaseMicroserviceController } from '../core/base/base-microservice.controller';
import { RequestContext } from '../dto';
import { DispatchService } from '../services';

@Controller('api/v1/example')
export class ExampleController extends BaseMicroserviceController {

    constructor (
        @Inject(RequestContext)
        protected requestContext: RequestContext,
        protected dispatcheService: DispatchService
    ) {
        super(dispatcheService);
    }

    @Get()
    test() {
        return 'test';
    }
}
要实现此简单功能,需要大量的解决方法IMHO 此外,我还有一篇文章描述了为什么使用基于范围的注入不好:https://guxi.me/posts/why-you-should-avoid-using-request-scope-injection-in-nest-js/

我的服务将是巨大的,有大量的控制器和大量的可注入服务。根据这篇文章-我的服务在性能和内存使用方面是不可伸缩的。

我的问题是如何在NestJS中实现我需要的功能,最佳实践是什么? 另一个&Quot;奖励问题&Quot;-RequestContext类有initialize方法,该方法接收快速请求并对其进行解析。我不喜欢它,我希望这个类的每个属性都是只读的,并通过使用request对象调用构造函数来以传统方式初始化这个类.如何使用@Inject策略实现此目标?

推荐答案

如果您希望在不使用请求作用域提供程序的情况下执行此操作,则只需用其他数据丰富请求对象就可以简化很多操作。无论您使用的是什么注入作用域,Request对象在技术上始终可用于入站HTTP交互。您可以完全放弃RequestContext,只需将所需的任何其他数据添加到侦听器内的请求对象中。

 intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest<Request>();
    const customRequestContext = initialize(request); // whatever you need to do to build this

    request.customRequestContext = customRequestContext;

    return next.handle();
}

使用custom decorator

可以很容易地在任何控制器中访问此值
export const RequestContext = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return request.customRequestContext;
  },
);

然后在您的任何控制器中,您都可以使用此命令访问该值:

@Get()
async findOne(@RequestContext() requestContext: RequestContextInterface) {
  // do whatever you need to do with it in your controllers
}

这篇关于初始化和传递请求上下文的最佳实践是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆