NestJS 后端开发 / 第 12 课
Nest 请求流程与 Express 路由对照
读取路径参数、查询和 DTO 请求正文,并准确追踪请求进入与返回的各个阶段。
上一课中,控制器把请求交给服务处理。这一课看完整的 HTTP 路径:取出客户端输入,验证后再调用服务。我们继续用内存便笺,不接数据库。Nest 和上一课的 Express 都能处理 HTTP;区别是 Express 通常在路由回调里手动读 req、检查数据、写 res,Nest 把这些工作拆进控制器、参数装饰器和可选的请求处理组件。
1. 路径、查询与正文
控制器可同时声明几种路由:
@Get(':id')
findOne(@Param('id') id: string) { /* ... */ }
@Get()
findAll(@Query('tag') tag?: string) { /* ... */ }
@Post()
create(@Body() input: CreateNoteDto) { /* ... */ }
GET /notes/7 的 7 是路径参数;GET /notes?tag=study 的 study 是查询参数;POST 的 JSON 正文例如 {"title":"HTTP","tag":"study"}。@Param、@Query、@Body 把相应位置的值交给方法。它们取出输入,不会自动证明输入符合业务要求。
示例 CreateNoteDto 描述正文应该有哪些字段。TypeScript 类型会在编译时检查代码,却会在运行时消失,所以仅写 title: string 并不能拒绝客户端发来的数字。我们在示例中为 POST 使用运行时 ValidationPipe 与 class-validator 装饰器;格式错误或字段为空时返回 400,有效正文才进入控制器。路径 ID 使用 ParseIntPipe 转为数字并拒绝非数字;可选查询 tag 则作为字符串交给服务筛选,不做额外格式限制。
2. Middleware、Guard、Pipe 与其余阶段
理解顺序时,把一次成功请求画成“进入处理器”和“返回响应”两半:
- **Middleware(中间件)**先运行,可以读写请求和响应,或调用
next()继续;常用于日志、通用预处理。 - **Guard(守卫)**判断当前请求是否允许访问。拒绝时不会进入后续控制器处理;登录授权是常见用途。
- Interceptor(拦截器)进入阶段在处理器前运行,可以记录开始时间、改变后续执行方式。
- **Pipe(管道)**对参数做转换或校验,例如把字符串参数转为数字、检查 DTO。管道在处理器调用前执行。
- **Handler(处理器)**即匹配到的控制器方法,通常再调用 provider 完成工作。
- 处理器正常返回后,Interceptor 返回阶段沿拦截器链反向执行,可改变响应值或记录耗时。
因此可记为:成功路径是 middleware → guard → interceptor(进入)→ pipe → handler → interceptor(返回)。若处理过程中抛出未处理异常,Nest 的**Exception Filter(异常过滤器)**负责生成错误响应;它不是成功路径上 Handler 后的固定一步。更内层拦截器可观察并处理错误,过滤器处理仍未被拦截器消化的异常。全局、控制器级、方法级的组件范围也会影响具体调用顺序,此处先看基本路径。
3. 跟 Express 对照
在 Express 示例里,我们写 app.get('/hello', (req, res) => ...),在回调中访问 req.params、req.query、req.body,自己调用 res.json(...)。JSON 中间件要先安装;校验也要手写。Nest 的 @Get() / @Post() 声明路由,参数装饰器把值传入方法,管道集中校验;正常返回对象会被 Nest 序列化为 JSON。Express 可以通过库或自己搭出相似层次,Nest 则把常见结构和依赖注入约定整合起来。
本例用于学习框架机制,不是 Leverage 后端真实实现。真实 OJ 还涉及身份认证、提交记录、队列和隔离评测等,本地内存便笺无法代替这些系统。
自己验证
向 POST /notes 发送 {"title":"","tag":"study"},观察状态码;再发送合法正文并访问 /notes/1。哪个阶段拦住了空标题?
**答案:**运行时校验管道在控制器处理器之前拒绝了正文,因此服务不会保存空标题。Express 初学时可在回调里手写同一检查;Nest 将它放进可复用的管道。
互动练习:追踪 Nest HTTP 请求管线
一个请求通过全局 middleware、guard、interceptor 和 pipe 后进入控制器;interceptor 还要包装响应。按调用方向排列。
- Interceptor 后置逻辑映射响应
- Controller handler 执行业务调用
- Pipe 转换或校验参数
- Interceptor 前置逻辑
- Guard 判断当前请求能否进入路由
- Middleware 处理请求并 next()
用 ↑ ↓ 调整顺序,再检查答案。也可以用 Tab 和回车操作。
路由参数装饰器负责取值,DTO 类型配合运行时管道校验;Nest 在处理器前后还有可组合的请求阶段。