【问题标题】:set request body size limit on NestJs for single controller在 NestJs 上为单个控制器设置请求正文大小限制
【发布时间】:2020-09-05 01:16:05
【问题描述】:

我想增加单个路由的请求正文大小限制,假设只针对路由/uploads,其余保持默认。

我知道你可以使用全局设置

app.use(json({ limit: '50mb' }));

或者,在纯 ExpressJS 中你可以使用

router.use('/uploads', express.json({ limit: '50MB' }));

但在 NestJS 中只有一个全局 app 和控制器类。例如

@Controller('uploads')
export class UploadController {
  constructor() {}

  @Post()
  create(...): Promise<any> {
    ...
  }
}

在哪里设置这个控制器的限制?

【问题讨论】:

    标签: node.js express nestjs


    【解决方案1】:

    您可以为此使用保护。

    import {
      Injectable,
      CanActivate,
      ExecutionContext,
      applyDecorators,
      UseGuards,
      SetMetadata,
    } from '@nestjs/common'
    import { Reflector } from '@nestjs/core'
    
    @Injectable()
    export class LimitGuard implements CanActivate {
      constructor(private reflector: Reflector) {}
    
      canActivate(context: ExecutionContext): boolean {
        const request = context.switchToHttp().getRequest()
        const limit = this.reflector.get<string[]>('limit', context.getHandler())
        return limit > request.socket.bytesRead
      }
    }
    
    export const Limit = (limit: number) =>
      applyDecorators(UseGuards(LimitGuard), SetMetadata('limit', limit))
    
    

    并且,在你的控制器中

      @Limit(1024 * 1024)
      @Post('your-path')
      async limitedMethod(): Promise<string> {
        // ...
      }
    

    【讨论】:

    • 这是否意味着例如 1GB 数据上传将首先加载到服务器,然后守卫会检查它是否大于限制?
    【解决方案2】:

    其实可以在 NestJS 中增加一条路由的大小限制,像这样:

         app.use('/uploads', json({ limit: '50mb' }));
         app.use(json({ limit: '100kb' }));
    

    需要第二条语句来重置所有其他路由的限制。

    【讨论】:

      【解决方案3】:

      您可以为所有路由设置一个上限,然后使用拦截器为每个控制器设置一个限制,而不是在 main.ts 中设置每个路由的大小限制。超过限制时,客户端会收到更具描述性的错误。

      import { Injectable, NestInterceptor, ExecutionContext, CallHandler, HttpException } from '@nestjs/common';
      import { Observable } from 'rxjs';
      
      @Injectable()
      export class SizeLimitInterceptor implements NestInterceptor {
          private sizeLimit = 0;
      
          constructor(sizeLimit: number) {
              this.sizeLimit = sizeLimit;
          }
      
          intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
              const ctx = context.switchToHttp();
              const request = ctx.getRequest();
              const response = ctx.getResponse();
              const size = request.socket.bytesRead;
      
              if (size > this.sizeLimit) {
                  throw new HttpException('Request Entity Too Large Error', 413);
              }
      
              return next.handle();
          }
      }
      

      你可以在你的控制器中像这样使用这个拦截器:

      @UseInterceptors(new SizeLimitInterceptor(1024 * 1024 * 10))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-03-16
        • 1970-01-01
        • 1970-01-01
        • 2019-12-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多