Node.js又一框架:Nest.js(五)

1,257 阅读4分钟

资源

Nest 为所有标准的 HTTP 方法提供了相应的装饰器:@Post()@Put()@Delete()@Patch()@Options() 以及 @Head() 等。

@All():用于定义一个处理所有 HTTP 请求方法的处理程序。

// 提供一个创建新记录的端点:POST 处理程序。
@Post('add') 
create(): string {
  return '新增一只猫咪';
}

路由通配符

路由支持模式匹配。

// ab*cd 将匹配 abcd,ab_cd,abecd 等
@Get('ab*cd')
findAll(): string {
  return '查询所有猫咪';
}
  1. 星号(*):通配符,将匹配任何字符组合。
  2. 连字符(-)和点(.):按字符串路径逐字解析。
  3. 字符 ?+* 以及 () 是它们的正则表达式对应项的子级。

状态码

默认情况下,响应的状态码总是默认为 200POST 除外(默认响应状态码为 201)。

可以通过在处理函数外添加 @HttpCode(...) 装饰器可以轻松更改此行为。

// 将 POST 的响应状态码由 201 调整为 204
@Post('add') 
@HttpCode(204)
create(): string {
  return '新增一只猫咪';
}

通常,状态码取决于各种因素,并不是固定的。可以通过 @Res() 注入使用类库特有的 response 对象,或者在出现错误时,抛出异常。

Headers

可以使用 @Header() 装饰器或类库特有的响应对象(直接调用 res.header())来自定义响应头。

@Post('add') 
@HttpCode(204)
@Header('Cache-Control', 'none')
create(): string {
  return '新增一只猫咪';
}

重定向

可以使用 @Redirect() 装饰器或特定于库的响应对象(直接调用 res.redirect())来将响应重定向到特定的 URL

@Redirect() 装饰器有两个可选参数,url 和 statusCodestatusCode 默认为 302

@Post('add') 
@HttpCode(204)
@Header('Cache-Control', 'none')
@Redirect('https://nestjs.com', 301)
create(): string {
  return '新增一只猫咪';
}

可以通过从路由处理方法返回一个如下格式的对象来动态决定 HTTP 状态代码或重定向 URL

{
  'url': string,
  'statusCode': number
}

返回的值将覆盖传递给 @Redirect() 装饰器的所有参数。如:

@Get('docs')
@Redirect('https://docs.nestjs.com', 302)
getDocs(@Query('version') version) {
  if (version && version === '7') {
    return { url: 'https://docs.nestjs.com/v7/' };
  }
}

路由参数

在路由路径中添加路由参数标记(token)以捕获请求 URL 中该位置的动态值,来定义带参数的路由。

以这种方式声明的路由参数可以在处理函数签名中添加 @Param() 装饰器来访问。

@Param() 装饰器用于修饰一个方法的参数(如:params),并在该方法内将路由参数做为被修饰的方法参数的属性(如:params.id)或其他通过装饰器传递的特定的参数标记。

// 以方法参数形式传递给装饰器,在方法主体内做为方法参数的属性来访问路由参数。
@Get(':id')
findOne(@Param() params): string {
  return `返回id为 ${params.id} 的猫咪`;
}

// 以特定的参数标记传递给装饰器,在方法主体中按参数名称直接访问路由参数。
@Get(':id')
findOne(@Param('id') id): string {
  return `返回id为 ${id} 的猫咪`;
}

子域路由

@Controller 装饰器可以接受一个 host 选项,以要求传入请求的 HTTP 主机匹配某个特定值。

@Controller('cats')
@Controller({ host: 'admin.example.com' })
export class CatsController {
  @Get('query')
  findAll(): string {
    return '查询所有猫咪';
  }
}

注意:当使用子域路由时,请使用默认的 Express 适配器(因为 Fastify 暂不支持嵌套路由器)。

类似路由参数,主机参数也支持动态传参:host 选项通过使用参数标识(token)来捕获主机名中该位置的动态值。

以这种方式声明的主机参数可以在处理函数签名中添加 @HostParam() 装饰器来访问。

@Controller({ host: ':account.example.com' })
export class AccountController {
  @Get()
  getInfo(@HostParam('account') account: string) {
    return account;
  }
}

作用域

Nest 中几乎所有内容都可以在传入的请求之间共享,如:数据库连接池,具有全局状态的单例服务。Node.js 并不遵循请求/响应多线程无状态模型(在该模型中,每个请求都由单独的线程处理),在 Nest 中,每个请求都由主线程处理。因此,使用单例实例对我们的应用程序来说是完全安全的。

但是,存在基于请求的控制器生命周期可能是期望行为的边缘情况,如:GraphQL 应用程序中的请求缓存,请求跟踪或多租户。

异步性

Nest 完美支持异步函数特性。

每个异步函数都必须返回一个 Promise。这意味着可以返回延迟值,Nest 将自行解析。

@Get()
async findAll(): Promise<any[]> {
  return [];
}

此外,通过返回 RxJS observable 流Nest 将自动订阅下面的源并获取最后发出的值(在流完成后)。

@Get()
findAll(): Observable<any[]> {
  return of([]);
}

请求负载

通过添加 @Body() 参数来给 POST 路由处理程序传递客户端参数。

首先通过使用 TypeScript 接口(Interface)或简单的类(Class)来定义 DTO(数据传输对象)模式,明确如何通过网络发送数据。

推荐使用

  1. 创建 CreateCatDto

    // create-cat.dto.ts
    
    export class CreateCatDto {
      readonly name: string;
      readonly age: number;
      readonly breed: string;
    }
    
  2. 使用该新创建的 DTO

    // cats.controller.ts
    
    @Post('add')
    async create(@Body() createCatDto: CreateCatDto) {
      return '新增一只猫咪';
    }
    

处理异常

【待完善】