
数据库 基础操作 和联表查询。本篇是教程的最终篇,虽然我们实现了 NestJs 的基础功能,但是真正的服务器需要做全局的数据核查、敏感操作落库和数据转化。
拥有这些能力才能让后台能力更加丰富,本篇将主要使用 NestJs 的高级能力,来实现这些功能。
本篇概要:
- 使用
guards 和 decorators 实现数据校验核查- 通过
interceptors 和 decorators 实现敏感操作录入- 自定义
pipes 实现数据转化完整示例可以在 github 找到。
守卫 Guards

在 请求到达业务逻辑前 会经过 guard,这样在接口前可以做统一处理。
例如:检查登陆态、检查权限 …
需要在业务逻辑前 统一检查 的信息,都可以抽象成守卫。
在真实场景中,大多数的后台管理端会用 JWT 实现接口鉴权。NestJs 也提供了对应的解决方案。
由于较长且原理相通,本篇暂时用校验 user 字段做演示。
新建守卫
新建 user.guard.ts 文件
1  | // src/common/guards/user.guard.ts  | 
单个接口使用守卫
单个接口使用需要用 @UseGuards 作为引用。再将定义的 UserGuard 作为入参。
在 student.controller.ts 中使用
1  | import { UseGuards /** ... **/} from '@nestjs/common';  | 
这样当访问 who-are-you 和 who-is-request 就起作用了
1  | // ❌ 不使用 user  | 
全局使用
全局使用仅需在 app.module.ts 的 providers 中引入。这样就对全局生效了
1  | import { APP_GUARD } from '@nestjs/core';  | 
这时再访问 get 请求 who-are-you 和 post 请求 who-is-request
1  | // ❌ get who-are-you  | 
自定义装饰器过滤
总有些接口我们不需要有 user 字段,这时自定义 decorator 就出马了。
基本原理是:在接口前设置 MetaData, 在服务启动时把 MetaData 写入内存,这样在请求过来时判断有无 MetaData 标签。有则通过,无则校验。
顺便也将 get 请求类型过滤掉。
1  | // common/decorators.ts  | 
user.guard.ts 改造
1  | // user.guard.ts  | 
NoUser 使用
1  | // students.controller.ts  | 
再调用时,就不会再校验了。
1  | // ✅  | 
这样就实现了全局守卫,但是部分接口不需要守卫的情况。
特别适用于登录态的校验,只有登陆接口不需要登录态,其他接口都需要登陆态或鉴权。
拦截器 Interceptors

拦截器工作在 请求前 和 响应后。它的原理和 decorator 类似,不同的是能做全局级别。
它的应用场景也非常广,例如:接口请求参数和请求结果的数据保存、设计模式中的 adapter 模式 等…
我们来用它实现敏感信息的数据保存。
它的原理和 guards 类似, 通过 decorator 加载到内存,知道哪些接口需要敏感操作记录,然后在调用接口时将 入参和结果存入。
涉及到数据库操作,因此需要新增模块和数据库连接。
新建敏感权限模块
新建敏感权限模块,包括 controller、module 和 service
1  | nest g controller sensitive  | 
创建 entity 文件
新建 sensitive.entity.ts 。
这里会用到 transformer, 原因是 mysql 底层并没有 Object 类型。需要通过 JS 把它存成 string 格式,在读取时用 object 格式。这样代码就不需要感知是啥类型了。
1  | import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn } from 'typeorm';  | 
引用数据库
和之前介绍数据库一样,在 sensitive.module.ts 中引入数据库
1  | import { Module } from '@nestjs/common';  | 
service 核心逻辑
敏感操作比较简单,service 仅需实现新增和查询。
先定义敏感操作类型
1  | // src/sensitive/constants.ts  | 
在修改 service,引入db操作
1  | // src/sensitive/sensitive.service.ts  | 
controller 修改
controller 比较简单,只需要简单的查询即可。敏感信息写入则是通过 decorator + interceptor 来实现
1  | // src/sensitive/sensitive.controller.ts  | 
新增装饰器
装饰器的用场来了,只需要告诉某个接口需要敏感操作记录,并指定类型即可。
1  | // src/common/decorators  | 
通过传参的方式,定义敏感操作的类型。在数据库中可以分类,通过索引的方式查找修改入参和结果。
拦截器
重点来了!!
和守卫权限校验类似,通过 reflector 取出内存中的 sensitive-operation 类型。
新建 src/common/interceptors/sensitive.interceptor.ts
1  | // src/common/interceptors/sensitive.interceptor.ts  | 
并在 app.module.ts 中引入全局。
1  | // app.module.ts  | 
其他模块引用
student 模块引入
1  | // src/students/students.controller.ts  | 
仅需要在接口前引入 @SensitiveOperation(SensitiveType.Set) 即可!是不是非常优美。
再来调用下!
1  | // ✅ 使用命令行调用  | 
bingo!这样就达到了我们想要的目的!
在不影响原有业务逻辑的情况下,仅是在接口处做标识的简单调用。实现了 AOP 的调用方式。对老代码的改造和新业务的编写都十分有用。
管道 Pipes

NestJs Pipes 的概念和 linux shell 的概念非常相似,都是通过前者的输出再做一些事情。
它的应用场景也非常广,例如:数据转化,数据校验等…
对数据输入时的操作非常有用。对复杂数据校验,例如表单数据等十分有用。
我们没有复杂输入,我们来使用简单的数据转化,实现在名字前加上🇨🇳
新建 Pipes
新建 src/common/pipes/name.pipes.ts。
1  | // src/common/pipes/name.pipes.ts  | 
和其他 NestJs 一样,都需要重载一边内置对象。Pipes 也需要重载 PipeTransform。
使用管道
在 controller 中使用 pipes。
1  | import { TransformNamePipe } from '../common/pipes/name.pipes';  | 
query 的第二个参数是 pipes, 也可以使用多个 pipes 对数据连续处理
调用接口
再浏览器访问
1  | // ✅  | 
这样就实现了简单版本的数据转换了!
总结
至此,NestJs 的入门篇章就结束了。
简单回顾下教程内容:
- 通过 
nest cli新建工程、新建模块 - 通过 
@Get和@Post实现 get、post 请求 - 通过 
dto限制对参数进行限制 - 自定义 
decorator实现参数获取、设置metadata - 调用内置 
log实现日志规范化 - 使用 
typeorm对数据库连接和基础操作,并进行联表操作及查询 - 使用 
guard对参数进行校验(可扩展成登录态) - 使用 
interceptor实现敏感数据落地 - 使用 
pipes实现数据格式化 
笔者也在 NestJs 逐渐探索中。它不仅包括简单的数据服务,还支持 GraphQL、SSE、Microservice 等等,是综合性非常强的框架。
btw:这是笔者用这么久以来最喜欢的 Node 框架了
感谢你的阅读~

