1. 前言
上一篇《Nest 快速入门》主要介绍NestJS的定位和快速入门例子,本文详细说说怎么在 NestJS 中进行 HTTP 请求和响应。
2. HTTP 协议回顾
2.1 HTTP 请求数据格式
举例:
规则:
2.2 HTTP 响应数据格式
举例:
规则:
3. 路由控制器
NestJS 控制器的目的是接收应用程序的特定请求,路由机制控制哪个控制器接收哪些请求。通常,每个控制器都有多个路由,并且不同的路由可以执行不同的操作。
通过装饰器和类创建控制器,装饰器将类与所需的元数据关联起来,并使 Nest 能够创建路由映射(将请求绑定到相应的控制器)。
- 通过 Nest CLI 工具,新建一个部门模块
js
nest g mo dept
生成文件如下:
js
import { Module } from '@nestjs/common';
import { DeptController } from './dept.controller';
@Module({
controllers: [DeptController],
})
export class DeptModule {}
- 新建 Controller 文件
js
nest g co dept
在生成的文件添加 findAll 方法
js
// src/dept/deptController.ts
import { Controller, Get } from '@nestjs/common';
@Controller('/depts')
export class DeptController {
@Get()
findAll(): Array<{ name: string; id: number }> {
return [
{
name: '学工部',
id: 1,
},
{
name: '教研部',
id: 2,
},
];
}
}
@Get()
表示当前请求的方法是 Get 方法,将会匹配 /depts
请求,然后执行 findAll()
方法,该方法返回的数据就是接口返回的数据,NestJS 会自动序列化为 JSON 字符串,并响应给客户端。
- dept 模块在 app 中注册如下:
js
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DeptModule } from './dept/dept.module';
@Module({
imports: [DeptModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
此时请求如下
4. NestJS 中的 HTTP 请求
Nest 为所有标准 HTTP 方法提供了装饰器:@Get()
、@Post()
、@Put()
、@Delete()
、@Patch()
、@Options()
和 @Head()
。
4.1 简单参数
下面两种跟随 url 上的参数
- urlParam 参数:比如根据 id 查询部门
/depts/:id
- query:分页查询员工数据
/emps?page=1&pageSize=10
4.1.1 urlParam
1.编写代码
js
import { Controller, Get, Param } from '@nestjs/common';
@Controller('/depts')
export class DeptController {
@Get()
findAll(): Array<{ name: string; id: number }> {
return [
{
name: '学工部',
id: 1,
},
{
name: '教研部',
id: 2,
},
];
}
@Get(':id')
findOne(@Param('id') id: string): { name: string; id: string } {
return {
name: '学工部',
id,
};
}
}
2.验证请求
4.1.2 query
1.重新构建一个员工模块
sh
nest g mo emp # 创建模块
nest g co emp # 创建控制器
nest g s emp # 创建业务服务,目前没用到
2.编写获取查询参数,通过 @Query
装饰器获取
js
import { Controller, Get, Query } from '@nestjs/common';
@Controller('/emps')
export class EmpController {
@Get()
findAll(@Query('page') page: number, @Query('pageSize') pageSize: number) {
return {
pageSize,
page,
list: [],
};
}
}
3.验证
4.2 复杂参数
- form urlencoded
- json
- form data
4.2.1 form urlencoded
form url encoded 通过 body 传输数据,也就是把 query 字符串放在了 body 里,同样需要做 url encode,指定 content type 为 application/x-www-form-urlencoded
js
// src/dept/dept.controller.ts
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
import { CreateDeptDto } from './dto/create-dept.dto';
@Controller('/depts')
export class DeptController {
@Post()
addEmp(@Body() createDeptDto: CreateDeptDto) {
return {
name: createDeptDto.name,
};
}
}
使用 Nest @Body
装饰器接受,Nest 会解析并把数据注入到 dto 中,dto 是 data transfer object,就是用于封装传输的数据的对象。
js
// src/dept/dto/create-dept.dto.ts
export class CreateDeptDto {
name: string;
}
验证如下:
这种方式目前不太常见,通常使用 json 的方式进行新增。
4.2.2 json
json 需要指定 content-type
为 application/json
,内容会以 JSON 的方式传输:
后端代码不需要做改动,同样使用 @Body
进行接收,Nest 内部会根据 content type
区分解析方式。
前面两种适合传输文本数据,如果是复杂的二进制文件,则考虑使用 formData
进行传输。
4.2.3 formData
formData 通过 - - - -
作为 boundary 分隔的数据,主要用于传输文件。前端指定 content-type multipart/form-data
,并且用 FormData
对象来封装传输的内容。
这里实现上传图像功能,这个图像可以作为员工图像。
js
@Post()
@UseInterceptors(
AnyFilesInterceptor({
dest: 'uploads/',
}),
)
create(
@Body() createEmptDto: CreateEmptDto,
@UploadedFiles() files: Array<Express.Multer.File>,
) {
console.log(createEmptDto);
console.log(files);
return {
success: true,
};
}
Nest 解析 form data 使用 FilesInterceptor
的拦截器,用 @UseInterceptors
装饰器启用,然后通过 @UploadedFiles
来取。非文件的内容,同样是通过 @Body
来取。
测试验证:
5. NestJS 中的 HTTP 响应
在 Controller
抓装饰器 声明的类上,会将方法返回值直接响应,如果返回值是对象或数组,将会转换为 JSON 格式响应。
其他情况,可以使用 @Res
获取响应对象,进行处理,Nest 的底层架构默认使用了 Express,这里的 Res 对象用法跟 Express 一致。
js
@Controller('/www')
export class WWWController {
@Get('')
async query(@Req() req, @Res() res) {
const { headers } = req;
let platform = 'pc';
if (headers['user-agent'].includes('Mobile')) {
platform = 'mobile';
}
res.redirect(`/fopFePortalServices/www/${platform}`);
}
}
小结
本文主要讲解了在 Nest 中主要使用 Controller
进行 HTTP 的请求与响应,通过 @Get
、@Post()
等装饰器实现路由声明,通过 @Param
、@Body
获取路由的参数,通过 @UploadedFiles
获取 formData 数据,并直接通过方法返回值响应数据给客户端。