常用装饰器
Nest 中实现功能,大多是通过装饰器完成,因此学习常用的装饰器就显得尤为重要。
@Controller
一般在controller文件中用于声明路由及controller
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}@Injectable、@Inject
@Injectable用于声明provider,可以是任意的class
@Injectable()
export class A {
}Provider可以用构造器注入
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}也可以使用@Inject用于声明属性注入
import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
@Inject(AppService)
private appService: AppService;
@Get()
getHello(): string {
return this.appService.getHello();
}
}属性注入要注意传入的token,可能是class 也可能是string
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
@Module({
imports: [],
controllers: [AppController],
providers: [
{
provide: 'token',
useFactory() {
return {
number: 1,
};
},
},
],
})
export class AppModule {}
// app.controller.ts
import { Controller, Get, Inject } from '@nestjs/common';
@Controller()
export class AppController {
@Inject('token')
private readonly appService: Record<string, any>;
@Get()
getHello() {
return this.appService.number;
}
}@Module
@Module() 装饰器采用单个对象,其属性描述模块:
providers | 将由 Nest 注入器实例化并且至少可以在该模块中共享的提供程序 |
|---|---|
controllers | 此模块中定义的必须实例化的控制器集 |
imports | 导出此模块所需的提供程序的导入模块列表 |
exports | 这个模块提供的 providers 的子集应该在导入这个模块的其他模块中可用。你可以使用提供器本身或仅使用其令牌(provide 值) |
// app.module.ts
import { Module, Global } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AaaModule } from './aaa/aaa.module';
@Global()
@Module({
imports: [AaaModule],
controllers: [AppController],
providers: [AppService],
exports: [AppService],
})
export class AppModule {}@Optional
声明可选对象,正常情况下,如果注入的依赖为空创建对象就会报错,但声明了可选的情况下没有对应的provider也可以正常创建对象。
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
// app.controller.ts
import { Controller, Get, Inject, Optional } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
@Inject(AppService)
private readonly appService: AppService;
@Optional()
@Inject('token')
private readonly token: Record<string, any>;
@Get()
getHello() {
return {
hi: this.appService.getHello(),
token: this.token,
};
}
}@Global
声明全局模块
执行nest g res aaa命令,生成一个aaa模块。
// aaa.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from 'src/app.service';
@Controller('aaa')
export class AaaController {
constructor(private readonly appService: AppService) {}
@Get('hhh')
getHi() {
return this.appService.getHello();
}
}
// aaa.module.ts
import { Module } from '@nestjs/common';
import { AaaService } from './aaa.service';
import { AaaController } from './aaa.controller';
@Module({
controllers: [AaaController],
providers: [AaaService],
})
export class AaaModule {}
// app.module.ts
import { Module, Global } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AaaModule } from './aaa/aaa.module';
@Global()
@Module({
imports: [AaaModule],
controllers: [AppController],
providers: [AppService],
exports: [AppService],
})
export class AppModule {}这个时候的aaa.module.ts里面是没有引入AppModule的(因为没有imports),其作用的是@Global。
@UseFilters
注入拦截器
执行nest g f app生成Filter,在controller中使用@UseFilters注入AppFilter
// app.filter.ts
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
} from '@nestjs/common';
import { Response } from 'express';
@Catch(HttpException)
export class AppFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const response: Response = host.switchToHttp().getResponse();
response.status(exception.getStatus()).json({
msg: exception.message,
});
}
}
// app.controller.ts
import {
Controller,
Body,
Post,
UseFilters,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { AppDto } from './app.dto';
import { AppFilter } from './app/app.filter';
@Controller()
export class AppController {
@Post()
@UseFilters(AppFilter)
getHi(@Body() body: AppDto) {
throw new HttpException('ccxcxz', HttpStatus.BAD_REQUEST);
return {
body,
};
}
}@UseGuards
注入守卫
执行nest g gu app生成Guard,在controller中使用@UseGuards注入AppGuard
// app.guard.ts
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class AppGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
console.log('context', context);
return true;
}
}
// app.controller.ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AppGuard } from './app/app.guard';
@Controller()
export class AppController {
@Get()
@UseGuards(AppGuard)
getGuards() {
return {
content: 11,
};
}
}@UseInterceptors
注入拦截器
执行nest g interceptor app生成Interceptor,在controller中使用@UseInterceptors注入AppInterceptor
// app.interceptor.ts
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class AppInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log('context', context);
return next.handle();
}
}
// app.controller.ts
import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { AppInterceptor } from './app/app.interceptor';
@Controller()
export class AppController {
@Get()
@UseInterceptors(AppInterceptor)
getInterceptors() {
return {
content: 11,
};
}
}@UsePipes
注入管道,使得入参转换
// app.controller.ts
import { Controller, Get, ParseIntPipe, UsePipes, Query } from '@nestjs/common';
@Controller()
export class AppController {
@Get()
@UsePipes(ParseIntPipe)
UsePipes(@Query('a') a: string) {
console.log('a', typeof a);
return typeof a;
}
}@SetMetadata
为路由处理方法设置元数据
// app.gurad.ts
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
import { Reflector } from '@nestjs/core';
@Injectable()
export class AppGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
// 使用 Reflector 获取路由方法的 role 元数据
const roles = this.reflector.getAllAndMerge('role', [
context.getHandler(),
context.getClass(),
]);
console.log('roles', roles);
return true;
}
}
// app.controller.ts
import { Controller, Get, UseGuards, SetMetadata } from '@nestjs/common';
import { AppGuard } from './app/app.guard';
@Controller()
export class AppController {
@Get()
@UseGuards(AppGuard)
@SetMetadata('role', ['user'])
getGuards() {
return {
content: 11,
};
}
}@Ip
获取请求ip
import { Controller, Get, Ip } from '@nestjs/common';
@Controller()
export class AppController {
@Get()
getIp(@Ip() ip: string) {
return {
ip,
};
}
}@Session
获取session对象
执行npm install express-session安装express中间件
获取不到ts类型提示,则需加执行一个命令npm install @types/express-session
接下来在main.ts中引入并且启用
// main.ts
import { NestFactory } from '@nestjs/core';
import * as session from 'express-session';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(
session({
secret: 'test',
cookie: {
maxAge: 10000,
},
}),
);
await app.listen(3000);
}
bootstrap();
// app.controller.ts
import { Controller, Get, Session } from '@nestjs/common';
@Controller()
export class AppController {
@Get()
getSession(@Session() session: Record<string, any>) {
session.visits = session.visits ? session.visits + 1 : 1;
return {
visits: session.visits,
};
}
}这时候每次发起请求时返回的visits都会加1
@Headers
获取请求头信息
// app.controller.ts
import { Controller, Get, Headers } from '@nestjs/common';
@Controller()
export class AppController {
@Get()
getHeaders(@Headers() headers: Record<string, any>) {
return {
headers,
};
}
}@Redirect
重定向至指定url
// app.controller.ts
import { Controller, Get, Headers, Redirect } from '@nestjs/common';
@Controller()
export class AppController {
@Get()
@Redirect('http://www.baidu.com')
getHeaders(@Headers() headers: Record<string, any>) {
return {
headers,
};
}
}@Catch
捕获异常
// app.filter.ts
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
} from '@nestjs/common';
import { Response } from 'express';
@Catch(HttpException)
export class AppFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const response: Response = host.switchToHttp().getResponse();
response.status(exception.getStatus()).json({
msg: exception.message,
});
}
}
// app.controller.ts
import {
Controller,
Body,
Post,
UseFilters,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { AppDto } from './app.dto';
import { AppFilter } from './app/app.filter';
@Controller()
export class AppController {
@Post()
@UseFilters(AppFilter)
getHi(@Body() body: AppDto) {
throw new HttpException('ccxcxz', HttpStatus.BAD_REQUEST);
return {
body,
};
}
}@HostParam
获取域名参数
注意:需要配合@Controller中的host字段使用,否则无法获取
将域名设置为127.:host.0.1,访问127.0.0.1:3000时 @HostParam会获取到:host所对应的值为0
import { Controller, Get, Headers, HostParam } from '@nestjs/common';
@Controller({ host: '127.:host.0.1', path: 'aaa' })
export class AppController {
@Get()
getHeaders(
@Headers() headers: Record<string, any>,
@HostParam() host: Record<string, any>,
) {
return {
headers,
...host,
};
}
}请求方法
@Get
设置路由为get方法
import { Controller, Get, Post, Delete, Options, Put } from '@nestjs/common';
import { AppService } from 'src/app.service';
@Controller('aaa')
export class AaaController {
constructor(private readonly appService: AppService) {}
@Get('hhh')
getHi() {
return this.appService.getHello();
}
}@Post
设置路由为post方法
import { Controller, Get, Post, Delete, Options, Put } from '@nestjs/common';
import { AppService } from 'src/app.service';
@Controller('aaa')
export class AaaController {
constructor(private readonly appService: AppService) {}
@Post('hhh')
getHi1() {
return this.appService.getHello();
}
}@Delete
设置路由为delete方法
import { Controller, Get, Post, Delete, Options, Put } from '@nestjs/common';
import { AppService } from 'src/app.service';
@Controller('aaa')
export class AaaController {
constructor(private readonly appService: AppService) {}
@Delete('hhh')
getHi2() {
return this.appService.getHello();
}
}@Put
设置路由为put方法
import { Controller, Get, Post, Delete, Options, Put } from '@nestjs/common';
import { AppService } from 'src/app.service';
@Controller('aaa')
export class AaaController {
constructor(private readonly appService: AppService) {}
@Put('hhh')
getHi4() {
return this.appService.getHello();
}
}@Options
设置路由为options方法
import { Controller, Get, Post, Delete, Options, Put } from '@nestjs/common';
import { AppService } from 'src/app.service';
@Controller('aaa')
export class AaaController {
constructor(private readonly appService: AppService) {}
@Options('hhh')
getHi3() {
return this.appService.getHello();
}
}请求对象
处理程序通常需要访问客户端请求的详细信息。Nest 提供对底层平台 请求对象 的访问(默认为 Express)。我们可以通过将 @Req() 装饰器添加到处理程序的签名来指示 Nest 注入它来访问请求对象。
// cats.controller.ts
import { Controller, Get, Req } from '@nestjs/common';
import { Request } from 'express';
@Controller('cats')
export class CatsController {
@Get()
findAll(@Req() request: Request): string {
return 'This action returns all cats';
}
}提示为了利用
express类型(如上面的request: Request参数示例),请安装@types/express软件包。
请求对象表示 HTTP 请求,并具有请求查询字符串、参数、HTTP 标头和正文的属性(阅读更多 此处)。在大多数情况下,没有必要手动获取这些属性。我们可以使用开箱即用的专用装饰器,例如 @Body() 或 @Query()。下面是提供的装饰器列表和它们代表的普通平台特定对象。
@Request(), @Req() | req |
|---|---|
@Response(), @Res()***** | res |
@Next() | next |
@Session() | req.session |
@Param(key?: string) | req.params / req.params[key] |
@Body(key?: string) | req.body / req.body[key] |
@Query(key?: string) | req.query / req.query[key] |
@Headers(name?: string) | req.headers / req.headers[name] |
@Req、@Request
两个装饰器是同一个对象,都是注入整个请求对象
// app.controller.ts
import { Controller, Get, Inject, Optional, Req } from '@nestjs/common';
import { Request } from 'express';
import { AppService } from './app.service';
@Controller()
export class AppController {
@Inject(AppService)
private readonly appService: AppService;
@Optional()
@Inject('token')
private readonly token: Record<string, any>;
@Get()
getHello(@Req() request: Request) {
console.log('request', request);
return {
hi: this.appService.getHello(),
token: this.token,
};
}
}@Res、@Response
两个装饰器是同一个对象,都是注入整个响应对象
注意:如果注入了响应对象后,需要手动响应,不想手动响应的话需要在参数中加上{passthrough: true},否则服务器则会一直没有响应。
// app.controller.ts
import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';
@Controller()
export class AppController {
@Get('hi')
getHi(@Res() response: Response) {
// 手动响应
response.end('hi');
}
@Get('hello')
getHi(@Res({passthrough: true}) response: Response) {
console.log('response', response);
// 无需手动响应
return 'hello'
}
}@Query
获取url后的参数,如localhost:3000/?a=1,获取a为1,适用于@Get、@Post等
// app.controller.ts
import { Controller, Get, Inject, Query } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
@Inject(AppService)
private readonly appService: AppService;
@Get()
getHello(@Query('a') a: string) {
console.log('a', typeof a);
return {
hi: this.appService.getHello(),
a,
};
}
@Post()
getHi(@Query('b') b: string) {
console.log('b', typeof b);
return {
b,
};
}
}@Param
获取路径中的参数,如localhost:3000/hi/1111,获取/hi/1111中的1111
注意:需要在路由参数中插入:参数名才能获取到
import { Controller, Get, Post, Param } from '@nestjs/common';
@Controller()
export class AppController {
@Get('/hello/:d')
getHello(@Param('d') d: string) {
return {
d,
};
}
@Post('/hi/:c')
getHi(@Param('c') c: string) {
return {
c,
};
}
}@Body
如果是Post请求,可以使用@Body获取body的参数(application/x-www-form-urlencoded类型)
注意:记得新增dto
// app.dto.ts
export class AppDto {
a: string;
b: string;
}
// app.controller.ts
import { Controller, Body, Post } from '@nestjs/common';
import { AppDto } from './app.dto';
@Controller()
export class AppController {
@Post()
getHi(@Body() body: AppDto) {
return {
body,
};
}
}@Next
转发处理函数
注意:类似于@Response,如果注入了@Next对象后,需要手动响应,否则服务器则会一直没有响应。
import { Controller, Get, Next } from '@nestjs/common';
import { NextFunction } from 'express';
@Controller()
export class AppController {
@Get()
useNext(@Next() next: NextFunction) {
next();
return {
content: 11,
};
}
@Get()
useNext1() {
return {
content: 222,
};
}
}相同路由的处理函数调用@Next后会执行下一个函数。