Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Node.js服务端开发教程 (三):NestJS的路由与控制器

Node.js服务端开发教程 (三):NestJS的路由与控制器

作者头像
一斤代码
发布于 2019-11-12 05:50:24
发布于 2019-11-12 05:50:24
3.7K00
代码可运行
举报
文章被收录于专栏:大前端开发大前端开发
运行总次数:0
代码可运行

不管做没做过软件开发,我们可能都知道:通过一个URL地址可以访问到一个网站的资源,比如页面、图片、文件等等。不同的地址,可能最终访问到的内容不同,也可能会访问到相同的内容。其实,每一个URL都是由网站的服务器端程序来接收并进行处理,最终定向到相应的资源。这种机制,在服务端程序中被称作路由

路由机制决定了请求与控制器之间的关系,即一个请求被分派到哪个控制器进行处理。通常服务端Web框架都会有路由机制,或简单、或复杂,但要实现的功能都是类似的。

比如在Express.js(也是NestJS的默认底层适配框架)中,它的路由定义会是这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 一个简单的 GET 方法路由
app.get('/products', function (req, res) {
  res.send('GET request handled!')
})

// 一个简单的 POST 方法路由

app.post('/products', function (req, res) {
  res.send('POST request handled!')
})

上面的这种方式,比较简单直观,通过函数的形式定义了一个路由匹配路径规则和对应的业务处理函数间的关系。

路由装饰器

而NestJS采用了另一种方式:使用装饰器。NestJS框架中定义了若干个专门用于路由处理相关的装饰器,通过它们,可以非常容易的将普通的class类装饰成一个个路由控制器。这个在我们的第一篇教程文章里生成的骨架代码中就已经看到过了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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();
  }
}

每个要成为控制器的类,都需要借助 @Controller 装饰器的装饰。该装饰器也可以传入一个路径参数,作为访问这个控制器的主路径:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Controller("home")

这样改写以后,本地访问的URL就变成了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 http://localhost:3000/home

而 @Get 装饰器是众多HTTP方法处理装饰器中的一个(其他的有@Post,@Put,@Delete,@Patch,@Options,@Head,@All),经过它装饰的类方法,可以对HTTP的Get方法请求进行响应。它可以接受一个字符串或一个字符串数组作为参数,这里的字符串可以是固定的路径,也可以是通配符路径,请看以下的例子组合:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 主路径为 home
@Controller("home")

// 1. 固定路径
// 可匹配到的访问路径:
//   http://localhost:3000/home/greeting
@Get("greeting")

// 2. 通配符路径(通配符可以有 ?, +, * 三种)
// 可匹配到的访问路径:
//   http://localhost:3000/home/say_hi
//   http://localhost:3000/home/say_hello
//   http://localhost:3000/home/say_good
//   ...
@Get("say_*")

// 3. 路径数组
// 可匹配到的访问路径:匹配上面1和2里的所有路径
@Get(["greeting", "say_*"])

// 4. 带参路径
// 可匹配到的访问路径:
//   http://localhost:3000/home/greeting/hello
//   http://localhost:3000/home/greeting/good-morning
//   http://localhost:3000/home/greeting/xxxxx
//   ...
@Get("greeting/:words")

标准模式和特定库模式

乍一看,标准模式和特定库模式,有点不知所云。那让我们再来回顾一下NestJS是一个什么样的框架,就能更清楚的了解这两个模式的区别。

如上图所示,NestJS是一个通过适配器来调用底层其他Web框架的一个上层框架。这些底层框架的API之间多多少少会存在一些差别,NestJS通过适配器抹平了大部分的差别,使得在大多数场景下,通过它封装的API就能完成工作。但是总会有些场景会用到那些没法被统一化封装的底层框架特有API,在这种情况下,我们需要获取和调用底层框架的原生对象或函数。

所以,使用NestJS通用API的方式称为标准模式;而使用特定底层库API的方式则被称为特定库模式

下面来看看这两种模式下的代码有什么区别。我们来实现一个可以接受URL Query String参数的控制器方法。

1. 标准模式的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Controller, Get, Query } from '@nestjs/common';

@Controller("home")
export class AppController {

  @Get("greeting")
  getHello(@Query("from") from: string): string {
    return `A greeting from ${from}`;
  }
}

2.特定库模式的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Controller, Get, Req, Res } from '@nestjs/common';
import { Request, Response } from 'express';

@Controller("home")
export class AppController {

  @Get("greeting")
  getHello(@Req() req: Request, @Res() res: Response) {
    const { from } = req.query;
    res.send(`A greeting from ${from}`);
  }
}

以上两段代码实现了一样的功能,它们都可以接收一个名为from的URL查询字符串参数,然后将拼接后的整个问候语输出到请求响应中去。可以通过这个URL试一下效果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
http://localhost:3000/home/greeting?from=一斤代码

浏览器中访问的效果如下:

虽然两段代码功能相同,但是写法上的差别看起来还是很明显的。

标准模式下的写法尽量避免使用特定的框架对象,比如:不会去直接使用底层框架的请求(Request)和响应(Response)对象及其属性/方法。就如上面的代码所示,当获取参数时,只需通过@Query装饰器就可以把URL上携带的参数填充到控制器的函数参数中。这样的代码保持了底层框架无关性,更容易复用,当替换底层框架的时候也更容易做迁移。

而特定库模式的写法,就会为控制器函数注入特定底层框架(比如示例代码中的Express)对象,直接调用底层框架对象提供的功能。这种方式带来的好处是更直接,可以使用到上层框架中所没有提供的功能。但是,如果你的应用在将来可能计划做底层框架替换,比如用性能更好的Fastify替换Express,那使用过多的特定库模式写法就会增加移植的工作量和难度。

所以在这两种模式的使用上,需要权衡利弊。大多数情况下,推荐使用标准模式,实在是遇到上层框架中完成不了的功能,才考虑使用特定库模式。

其他常用装饰器的功能示例

一、@Param - 路径参数装饰器

当我们的URL中有一部分是动态的,比如下面的三个:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
http://www.myblog.com/articles/20191110
http://www.myblog.com/articles/20191111
http://www.myblog.com/articles/20191112

上面这些地址看起来是一个博客网站系统按日期查看文章的页面,地址最后的日期部分,肯定是不固定的,输入每一个日期查看到的结果都可能会不一样。对于这种情况,服务端程序是不太可能会为每一个日期都编写一个控制器函数(除非写这个网站的程序员是个奇葩),最可能的情况就是只有一个控制器函数,这个函数能从URL上获取动态的日期这部分信息,然后根据获取到的日期去数据库查询对应日期的文章信息。

如果用NestJS来实现,看起来就会是这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Controller, Get, Param } from '@nestjs/common';

@Controller("articles")
export class ArticleController {

  @Get(":date")
  getArticles(@Param("date") date: string): string {
    return `Articles for ${date}`;
  }
}

二、@Post + @Body - 获取POST请求的请求体

当我们向服务端发送POST请求的时候,参数一般都会是放入请求体进行携带的,它可以比URL查询字符串携带更多的数据量。在NestJS里处理POST请求以及获取请求体参数,是这样做的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface CreateArticleDto {
    title: string;
    content: string;
}

// ....

@Post()
async create(@Body() article: CreateArticleDto) {
  console.log(article);
  this.articleService.create(article);
  return 'New article is created';
}

如果我们去请求这个POST形式的API,并传入一个JSON格式的请求体参数给它:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "title": "逆天啦!某程序员写了一斤代码!",
  "content": "据了解,该程序员的硬盘重达一斤。"
}

则控制器的 create 函数参数 article 就会被接收到的JSON数据所填充,控制台打印出来的内容如下:

三、@Headers和@Header - 获取请求头和设置响应头

我们经常会使用HTTP头来在客户端和服务端传递信息,比如:通过请求头来携带登录授权的Authorization令牌值;或者为响应头设置Access-Control-Allow-Origin值,指定可进行跨域调用的域名规则,等等。在NestJS中我们可以通过装饰器来很方便的实现对请求头的访问和操作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Post("test")
@Header('x-my-resp', '123')
test(@Headers("x-my-val") myHeaderVal: string) {
  return `x-my-val is ${myHeaderVal}`
}

上面的代码中,我们通过 @Headers 装饰器获取请求头中名为x-my-val的头信息;并使用 @Header 装饰器在相应头中添加了一个名为x-my-resp的自定义头。

下面是使用API测试工具进行测试的结果:

总结

路由和控制器是编写服务端API的工作中,非常基础又非常重要的一环,先熟悉和理解基本的用法,然后深入思考和研究它们的实现原理,这些知识在服务端编程中都是共通的,无论在Node.js、Java、亦或是Go等,都遵循着同样的底层协议体系、相似的应用框架设计。掌握它们吧!让服务端程序在你的手中被精准的控制。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Node.js服务端开发教程 (一):NestJS框架0到1
要做Node.js编程嘛,Node.js是必须安装的,大家可以到官网(https://nodejs.org)下载安装,推荐安装LTS版本。
一斤代码
2019/11/04
2.8K0
2024 版:Node.js+Express+Koa2+Nest.js 开发服务端(高の青)
在现代的 web 开发中,Node.js 是一种非常流行的服务器端 JavaScript 环境。我们来编写一个大致的框架和一些关键代码片段,以帮助你了解如何使用 Node.js、Express、Koa2 和 Nest.js 开发服务端应用。
百课优用户
2024/07/29
4470
使用NestJS搭建服务端应用
最近有个需求需要基于前端技术栈实现一套中间层API接口,用于处理由前端维护的一套JSON配置文件。
神奇的程序员
2022/04/10
2.2K0
使用NestJS搭建服务端应用
学完这篇 Nest.js 实战,还没入门的来锤我!(长文预警)
最近接到一个小需求,需要自己全干(前端+后端),看到群里大家对Nest.js热情都很高,自己也心痒痒,所以就走上了 Nest.js 的不归路~
玖柒的小窝
2021/11/21
11K0
学完这篇 Nest.js 实战,还没入门的来锤我!(长文预警)
面试官:说一下大文件分片下载
但是,这样文件是全部读取出来返回,如果文件大了,比如好几个 G,会占用很大的内存。
神说要有光zxg
2024/04/30
5550
面试官:说一下大文件分片下载
Node.js服务端开发教程 (四):依赖注入基础篇
现代的服务业真是越做越到位了,我们只要提供出我们的需求,就会有人主动来提供服务,针对性的解决我们的问题。就如上面的打车服务一样,我们不再需要像以前一样,在寒风凛冽的马路上、大雨瓢泼的黑夜里,哆哆嗦嗦的招手拦车,一辆辆的问司机走不走,司机大哥忙着要下班,不走;司机大哥还没吃饭,不走;司机大哥心情不好,不走;路程太近,不走;路程太远,不走......我们只需要在温暖的房间里向打车软件系统告知我们的行程信息、偏好信息等,就会有愿意服务我们的司机上门为我们服务。
一斤代码
2019/11/12
1.7K0
Node.js服务端开发教程 (七):模块系统
说到“模块”两字,我们脑海里肯定会浮现很多关于它好处的词汇:封装性、可复用、按需引入等等。当一个软件系统的代码规模上升到一定复杂度后,我们的确需要一些方式来条理更清晰的组织我们的代码,让代码更易阅读、团队分工协作更方便。
一斤代码
2019/11/29
1.6K0
Nest.js 从零到壹系列(一):项目创建&路由设置&模块
本系列将以前端的视角进行书写,分享自己的踩坑经历。教程主要面向前端或者毫无后端经验,但是又想尝试 Node.js 的读者,当然,也欢迎后端大佬斧正。
一只图雀
2020/04/07
5.6K0
Nest.js Controller 解析:探索路由和请求处理的强大功能
Controller  它 主要是负责 特定路由请求处理并将响应结果返回给客户端。
程序员海军
2023/11/03
6370
NestJS学习总结篇
完整版本,点击此处查看 http://blog.poetries.top/2022/05/25/nest-summary
前端进阶之旅
2022/05/27
2.5K0
Node.js学习笔记(三)——Node.js开发Web后台服务
Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。 使用 Express 可以快速地搭建一个完整功能的网站。使用Node.js作为AngularJS开发Web服务器的最佳方式是使用Express模块。
张果
2022/09/28
8.4K0
Node.js学习笔记(三)——Node.js开发Web后台服务
Nest系列教程之控制器
为了创建一个基本的控制器,我们必须将元数据附加到类中。Nest 知道如何映射我们的控制器到相应的路由。
阿宝哥
2019/11/06
1.9K0
Nest系列教程之控制器
NestJS中使用Guard实现路由保护
NestJS中Guard是一种用于保护路由的机制。它可以在路由处理之前执行一些逻辑,例如验证用户身份、检查权限等。
kongxx
2024/09/11
2320
NestJS中使用拦截器
在NestJS中,拦截器是一种强大的工具,可以用来在请求处理的不同阶段执行一些操作。拦截器可以用于日志记录、验证、转换请求和响应等任务。今天就看看如何在NestJS中使用拦截器。
kongxx
2024/09/11
1970
快速打开 Nestjs 的世界
src目录是主要的源码目录,主要由入口文件 main.ts 和 一组 module,service,controller构成。
前端小鑫同学
2023/12/04
8190
快速打开 Nestjs 的世界
学完这篇 Nest.js 实战,还没入门的来锤我!(长文预警)
最近接到一个小需求,需要自己全干(前端+后端),看到群里大家对Nest.js热情都很高,自己也心痒痒,所以就走上了Nest.js的不归路~
五月君
2021/11/30
15.1K2
学完这篇 Nest.js 实战,还没入门的来锤我!(长文预警)
NestJS 7.x 折腾记: (5) 管道,一个好玩的东西!比如入参校验!
意思就git的提交记录以单行显示的前三条,而且提交概要中有build这个词的 在nest里面的管道,主要是用来做入参数据类型的拦截转换; 跟ng提供的概念差不多,大同小异~~
CRPER
2022/03/08
1.2K0
NestJS 7.x 折腾记: (5) 管道,一个好玩的东西!比如入参校验!
10分钟上手nest.js+mongoDB
项目中我们会用到 Mongoose 来操作我们的数据库,Nest 官方为我们提供了一个 Mongoose 的封装,我们需要安装 mongoose 和 @nestjs/mongoose:
淼学派对
2024/04/10
5350
BFF与Nestjs实战
主题列表:juejin, github, smartblue, cyanosis, channing-cyan, fancy, hydrogen, condensed-night-purple, greenwillow, v-green, vue-pro, healer-readable, mk-cute, jzman, geek-black, awesome-green, qklhk-chocolate
乐圣
2022/11/19
2.9K0
BFF与Nestjs实战
nestjs搭建HTTP与WebSocket服务
最近在做一款轻量级IM产品,后端技术栈框架使用了nodejs + nestjs作为服务端。同时,还需要满足一个服务同时支持HTTP服务调用以及WebSocket服务调用,此文主要记录本次搭建过程,以及基本的服务端设计。
w4ngzhen
2023/10/17
9000
nestjs搭建HTTP与WebSocket服务
推荐阅读
相关推荐
Node.js服务端开发教程 (一):NestJS框架0到1
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验