Nest
官網:https://nestjs.com/
中文網站:https://docs.nestjs.cn/
評價: https://mp.weixin.qq.com/s/Y67O9ks-qPwVF8UqHaRY-g
Nest 是一個漸進的 Node.js 框架,可以在 TypeScript 和 JavaScript (ES6、ES7、ES8)之上構建高效、可伸縮的企業級服務器端應用程序。
Nest 基於 TypeScript 編寫並且結合了 OOP(面向對象編程),FP(函數式編程)和 FRP (函數式響應編程)的相關理念。在設計上的很多靈感來自於 Angular,Angular 的很多模式又來自於 Java 中的 Spring 框架,依賴注入、面向切面編程等,所以我們也可以認為:Nest 是 Node.js 版的 Spring 框架。
Nest 框架底層 HTTP 平台默認是基於 Express 實現的,所以無需擔心第三方庫的缺失。
Nest 旨在成為一個與平台無關的框架。 通過平台,可以創建可重用的邏輯部件,開發人員可以利用這些部件來跨越多種不同類型的應用程序。
從技術上講,Nest 可以在創建適配器后使用任何 Node HTTP 框架。有兩個支持開箱即用的 HTTP 平台:express 和 fastify。您可以選擇最適合您需求的產品。
NestJs 的核心思想:就是提供了一個層與層直接的耦合度極小,抽象化極高的一個架構體系。
建立項目
//安裝Nest CLI
npm i -g @nestjs/cli .
//使用Nest CLI 創建項目
nest new project-name
// 運行項目
npm run start
src目錄核心文件
app.controller.ts | 帶有單個路由的基本控制器示例。 |
---|---|
app.module.ts | 應用程序的根模塊。 |
main.ts | 應用程序入口文件。它使用 NestFactory 用來創建 Nest 應用實例。 |
NEST命令行工具
nest --help
可以列出命令行的主要命令以及幫助
創建
- new(簡寫n)[options] [name] :創建一個NEST應用,例如 nest n hello-world。選項中支持:
- --directory 指定目標目錄
- -d或--dry-run 不輸出創建過程中的報告
- -g或--skip-git 不要初始化git倉庫(默認是會在項目創建git倉庫)
- -s或--skip-install 不要安裝依賴哭
- -p或--package-manager [name] 指定包管理工具
- -l或--language [lang] 指定語言JS或者TS
- -c或--collection [name] 用特定的架構生成項目
構建
- build [options] [app] : 構建項目,默認會將TS文件構建到項目的dist目錄中;options有:
- -c或--config [path] 用cli構建時特定的配置文件
- -p或--path [path] tsconfig配置文件
- -w或--watch 實時重加載,觀察模式
- --watchAssets 觀察非ts文件模式
- --webpackPath [path] webpack的配置文件
- --tsc 使用tsc編譯
運行
- start [options] [app]:運行NEST項目,options有:
- -c或--config [path] 用cli構建時特定的配置文件
- -p或--path [path] tsconfig配置文件
- -w或--watch 實時重加載,觀察模式
- --watchAssets 觀察非ts文件模式
- -d或--debug [hostport] 調試模式
- --webpack用webpack編譯
- --webpackPath [path] webpack的配置文件
- --tsc 使用tsc編譯
- -e或--exec [binary] 以二進制運行(默認用node)
- --preserveWatchOutput tsc的觀察模式
更新
- update或u [options]:更新當前項目的依賴組件
- -f或--force 強制重新安裝依賴
- -t或--tag 升級被打上(latest | beta | rc | next tag)的組件
Nest架構元素
其類型如下表:
名稱 | 別名 | 說明 |
---|---|---|
application | application | 在工作區中創建一個新的應用 |
class | cl | 新的類 |
configuration | config | 命令行的配置文件 |
controller | co | 控制器 |
decorator | d | 自定義裝飾器 |
filter | f | 過濾器 |
gateway | ga | 請求的網關 |
guard | gu | 守衛 |
interceptor | in | 攔截器 |
interface | interface | 接口 |
middleware | mi | 中間件 |
module | mo | 模塊 |
pipe | pi | 管道 |
provider | pr | 功能組 |
resolver | r | GraphQL處理器 |
service | s | 服務 |
library | lib | 單獨庫模式下創建一個庫 |
sub-app | app | 子應用 |
resource | res | 一個數據模型的CRUD |
平台
Nest 旨在成為一個與平台無關的框架。 通過平台,可以創建可重用的邏輯部件,開發人員可以利用這些部件來跨越多種不同類型的應用程序
有兩個支持開箱即用的 HTTP 平台:express 和 fastify
暴露自己的 API分別是 NestExpressApplication 和 NestFastifyApplication
const app = await NestFactory.create<NestExpressApplication>(AppModule);
控制器
控制器負責處理傳入的 請求 和向客戶端返回 響應
創建一個基本的控制器:類和裝飾器
CLI 創建控制器
$ nest g controller cats
路由
Nestjs 中沒有單獨配置路由的地方。定義好控制器后 nestjs 會自動給我們配置對應的路由
//中控制器內直接用裝飾器匹配路由
@Get()
index() {
//輸出內容
return '我是article控制器get請求';
}
兩種不同的操作響應:** 標准(推薦)和 類庫**
關於 nest 的 return: 當請求處理程序返回 JavaScript 對象或數組時,它將自動序列化為JSON。但是,當它返回一個字符串時,Nest 將只發送一個字符串而不是序列化它。這使響應處理變得簡單:只需要返回值,Nest 負責其余部分。
類庫響應方式
通過 @Res() 注入類庫特定的 響應對象
import { Controller, Get, Post, Res, HttpStatus } from '@nestjs/common';
import { Response } from 'express';
@Controller('cats')
export class CatsController {
@Post()
create(@Res() res: Response) {
res.status(HttpStatus.CREATED).send();
}
@Get()
findAll(@Res() res: Response) {
res.status(HttpStatus.OK).json([]);
}
}
類庫方式失去了與依賴於 Nest 標准響應處理的 Nest 功能的兼容性,例如攔截器和 @HttpCode() 裝飾器。此外,您的代碼可能變得依賴於平台(因為底層庫可能在響應對象上有不同的 API),並且更難測試(您必須模擬響應對象等)。因此,在可能的情況下,應始終首選 Nest 標准方法
裝飾器
裝飾器將類與所需的元數據相關聯,並使 Nest 能夠創建路由映射
請求裝飾器
Nestjs也提供了其他HTTP請求方法的裝飾器 @Put() 、@Delete()、@Patch()、 @Options()、 @Head()和 @All()
用法都差不多
import { Controller, Get } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll(): string {
return 'This action returns all cats';
}
}
獲取Get 傳值或者Post 提交的數據
@Request() | req |
---|---|
@Response() | res |
@Next() | next |
@Session() | req.session |
@Param(key?: string) | req.params / req.params[key] |
@Body(key?: string) | req.body / req.body[key] |
@Query(key?: string) | req.query / req.query[key] |
@Headers(name?: string) | req.headers / req.headers[name] |
import {Body, Controller, Get, Post, Query, Request} from '@nestjs/common';
@Controller('article')
export class ArticleController {
//get請求
@Get()
index() {
//輸出內容
return '我是article控制器';
}
//路由拼接article/add
@Get('add')
//獲取url裝飾器(get參數)
addArticle(@Query() query) {
console.log(query)
//輸出內容
return '我是article/add';
}
@Get('edit')
//request裝飾器獲取請求信息
editArticle(@Request() req){
console.log(req.query)
return "我是article/edit"
}
@Post('create')
//Body裝飾器獲取post內容
create(@Body() body){
console.log(body)
return '我是Post請求'
}
}
狀態碼
@HttpCode
@Post()
@HttpCode(204)
create() {
return 'This action adds a new cat';
}
重定向
@Redirect()
@Get()
@Redirect('https://nestjs.com', 301)
子域路由
@Controller 裝飾器可以接受一個 host 選項,以要求傳入請求的 HTTP 主機匹配某個特定值
@Controller({ host: 'admin.example.com' })
export class AdminController {
@Get()
index(): string {
return 'Admin page';
}
}
動態路由
不常用
注意動態路由要放在下面,不然會先匹配,下面路由匹配不成功
import {Controller, Get, Param, Query} from '@nestjs/common';
@Controller('news')
export class NewsController {
@Get()
addDate(@Query('id') id){
console.log(id)
return "獲取里面參數"
}
//news/123
@Get(":id")
index(@Param() param){
//{id: '123'}
console.log(param)
return "我是動態路由"
}
}
請求負載
使用 TypeScript, POST接受客戶端參數,需要確定 DTO(數據傳輸對象)模式
DTO是一個對象,它定義了如何通過網絡發送數據,通過使用 TypeScript接口或簡單的類實現(推薦使用類)
區別:類是JavaScript ES6標准的一部分,因此它們在編譯后的 JavaScript中保留為實際實體。另一方面,由於 TypeScript接口在轉換過程中被刪除
創建 CreateCatDto 類
create-cat.dto.ts
export class CreateCatDto {
readonly name: string;
readonly age: number;
readonly breed: string;
}
它只有三個基本屬性。 之后,我們可以在 CatsController中使用新創建的DTO
cats.controller.ts
@Post()
async create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
完整示例
import { Controller, Get, Query, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { CreateCatDto, UpdateCatDto, ListAllEntities } from './dto';
@Controller('cats')
export class CatsController {
@Post()
create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
@Get()
findAll(@Query() query: ListAllEntities) {
return `This action returns all cats (limit: ${query.limit} items)`;
}
@Get(':id')
findOne(@Param('id') id: string) {
return `This action returns a #${id} cat`;
}
@Put(':id')
update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) {
return `This action updates a #${id} cat`;
}
@Delete(':id')
remove(@Param('id') id: string) {
return `This action removes a #${id} cat`;
}
}
最后一步
控制器已經准備就緒,但是 Nest 不知道 CatsController 是否存在
app.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
@Module({
controllers: [CatsController],
})
export class AppModule {}
使用 @Module()裝飾器將元數據附加到模塊類,Nest 現在可以輕松反映必須安裝的控制器
配置靜態資源
nest若要加載靜態資源則需要配置靜態資源目錄
入口文件src/main
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
//入口文件引入express平台HTTP平台
import { NestExpressApplication } from '@nestjs/platform-express'
//引入path模塊的join方法
import {join} from "path";
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
// app.useStaticAssets('public'); //配置靜態資源目錄
app.useStaticAssets(join(__dirname, '..', 'public'), { //配置虛擬目錄
prefix: '/static/', //設置虛擬路徑
});
await app.listen(3000);
}
bootstrap();