NestJS 中 HTTP请求与响应

1. 前言

上一篇《Nest 快速入门》主要介绍NestJS的定位和快速入门例子,本文详细说说怎么在 NestJS 中进行 HTTP 请求和响应。

2. HTTP 协议回顾

2.1 HTTP 请求数据格式

举例:

规则:

2.2 HTTP 响应数据格式

举例:

规则:

3. 路由控制器

NestJS 控制器的目的是接收应用程序的特定请求,路由机制控制哪个控制器接收哪些请求。通常,每个控制器都有多个路由,并且不同的路由可以执行不同的操作。

通过装饰器和类创建控制器,装饰器将类与所需的元数据关联起来,并使 Nest 能够创建路由映射(将请求绑定到相应的控制器)。

  1. 通过 Nest CLI 工具,新建一个部门模块
js 复制代码
nest g mo dept

生成文件如下:

js 复制代码
import { Module } from '@nestjs/common';
import { DeptController } from './dept.controller';

@Module({
  controllers: [DeptController],
})
export class DeptModule {}
  1. 新建 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 字符串,并响应给客户端。

  1. 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-typeapplication/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 数据,并直接通过方法返回值响应数据给客户端。

相关推荐
星辰徐哥11 小时前
Spring Boot 微服务架构设计与实现
spring boot·后端·微服务
星辰徐哥11 小时前
Spring Boot 数据导入导出与报表生成
spring boot·后端·ui
明夜之约11 小时前
Spring Boot 自动装配源码
java·spring boot·后端
Leaton Lee11 小时前
Spring Boot分层架构详解:从Controller到Service再到Mapper的完整流程
java·spring boot·后端·架构
Micro麦可乐11 小时前
Spring Boot 实战:从零设计一个短链系统(含完整代码与数据库设计)
数据库·spring boot·后端·哈希算法·雪花算法·短链系统
Jinkxs11 小时前
Resilience4j- 与 Spring Boot 快速集成:自动配置与基础注解使用
java·spring boot·后端
毕设源码_郑学姐11 小时前
计算机毕业设计springboot网络相册设计与实现 基于Spring Boot框架的在线相册管理系统开发与应用 Spring Boot驱动的网络影集设计与实践
spring boot·后端·课程设计
辣机小司11 小时前
【踩坑记录:Spring Boot 配置文件读取值不一致?警惕 YAML 的“八进制陷阱”与 SnakeYAML 版本之谜】
java·spring boot·后端·yaml·踩坑记录
码农阿豪11 小时前
从零到一:Spring Boot快速接入金仓数据库实战
数据库·spring boot·后端
追逐时光者11 小时前
一个基于 .NET 与 Avalonia 构建、面向 TrinityCore 的开源 WoW 数据库编辑器
后端·.net