nest.js學習筆記(一)


1、前期准備工作

環境配置參考node里的nodemon或者webpack

在學習nest.js前需要了解它的反映機制 Reflect.defineMetadata, 學習這個需要安裝和引入庫‘reflect-metadata’這個庫

npm i reflect-metadata --save
import 'reflect-metadata'

console.log(Reflect.defineMetadata); //可以打印出對應的方法說明安裝成功

Reflect-Metadata的方法介紹

import 'reflect-metadata' let Info = { name: 'aaa', getName() { return this.name }, } //定義在對象上的元數據
Reflect.defineMetadata('info', '這是個對象元數據信息', Info) let msg = Reflect.getMetadata('info', Info) console.log(msg) //定義在對象屬性上的元數據
Reflect.defineMetadata('paramInfo', '這是個對象屬性元數據', Info, 'name') let paramMsg = Reflect.getMetadata('paramInfo', Info, 'name') console.log(paramMsg) //判斷元數據上是否有指定的數據
console.log(Reflect.hasMetadata('info', Info)) // true
console.log(Reflect.hasMetadata('paramInfo', Info, 'getName')) // false

//如果子類繼承了父類原型鏈上的方法,那么同時也會繼承原型鏈上的metadata,這個時候就可以使用hasOwnMetadata來判斷是否是自有的屬性
console.log(Reflect.hasOwnMetadata('info', Info))

注意:使用defineMetadata不會影響原數據本身,只會增加元數據

Reflect中類中的使用

import 'reflect-metadata' @Reflect.metadata('name', 'metaData_className') //這個是直接定義,相當於defineMetadata
class Test { @Reflect.metadata('name', 'metaData_className_state') public state?: string @Reflect.metadata('name', 'metaData_className_method') public check(param: string): void {} } console.log(Reflect.getMetadata('name', Test)) console.log(Reflect.getMetadata('name', Test.prototype, 'state')) console.log(Reflect.getMetadata('name', Test.prototype, 'check')) //獲取所有的原型上的key值
console.log(Reflect.getMetadataKeys(Test.prototype)) //獲取原型上指定屬性的key值
console.log(Reflect.getMetadataKeys(Test.prototype, 'state')) // 注意: 特殊類型 // design:type 表示屬性的聲明的類型 // design:paramtypes 表示函數參數的聲明類型,返回的是一個數組 // design:returntype 表示函數的返回類型

注意:Reflect.metadata如何修復的是屬性或者類里的方法,那么相當對應的屬性值是掛載在prototype原型上

可以通過自己寫裝飾器,將這個東西封裝入自己封裝的裝飾器中

import 'reflect-metadata' const classMetadata = <T>(name: string, value: string|number|boolean) => { return (classT: T) => { Reflect.defineMetadata(name, value, classT) } } const methodMetadata = <T>(name: string, value: string|number|boolean) => { return (classT: T, methodT: string|symbol) => { Reflect.defineMetadata(name, value, classT, methodT) } }

@classMetadata('name', 'ven')
class Test {

    @methodMetadata('name', 'state')
    public state: string

    @methodMetadata('name', 'method')
    public check(param: string): void {
    }
}

console.log(Reflect.getMetadata('name', Test)) console.log(Reflect.getMetadata('name', Test.prototype, 'state')) console.log(Reflect.getMetadata('name', Test.prototype, 'check'))

依賴注入小試

import 'reflect-metadata' class Logger { public constructor() { console.log('this is logger') } public getLog() {} } // 使用依賴注入,實例化聲明屬性的類 function Inject(injectId: string): PropertyDecorator { return function (targetClassPrototype, propName) { let PropClass = Reflect.getMetadata('design:type', targetClassPrototype, propName) let PropClassObj = new PropClass() console.log(PropClassObj) } } class Active { @Inject('Logger') public log?: Logger public getPeo() { return this.log } } //使用依賴注冊實例化構造器參數中聲明的類 function InjectContructor(injectId?: string): ParameterDecorator { return function (targetClassPrototype, propertyKey, parameterIndex) { let propClass = Reflect.getMetadata('design:paramtypes', targetClassPrototype) let loggerClass = new propClass[parameterIndex]() } } class Person { public constructor(@InjectContructor('Logger') private logger: Logger, private count: number) {} }

注意:以上方法的使用需要建立在tsconfig.json中target:es5的基礎上,否則獲取不到相關的值

2、nest框架的安裝

$ npm i -g @nestjs/cli
$ nest new project-name

3、nest結構介紹

 

在nest.js中路徑是指向根目錄下,如 src/controllers表示的是根目錄下的controllers文件夾

4、controller的使用

 controller的創建,可以使用命令:

nest g controller 模塊名稱

就會獨立生成指定文件的模塊,里面有 模塊名稱.controller.ts   模塊名稱.controller.spec.ts

controller的入門案例

import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; @Controller() //前綴是/
export class AppController { // 只需要在構造函數里聲明依賴,IOC窗容器會自動幫你注入實例,你直接調用就可以了
 constructor(private readonly appService: AppService) {} @Get() //表示的是/的響應, 控制器里面一般只用於接收參數,返回響應,並不會真正處理業務
 getHello(): string { return this.appService.getHello(); } @Get('api')  // 訪問的/api的路徑進行響應的
  getApi(): Array<string> { return ['aa', 'bbb', 'cc'] } }

注意:在使用controller的時候 @controller('prefix')是表示一個控制器的修飾符,prefix表示訪問路徑的前綴,如@controller('user'), 那么@get('/api')時則表示訪問/user/api路徑時的響應, 這里的@get表示發送請求的類型是get

 controller方法的響應方式

通常來講,controller里的響應會自動返回200的狀態碼,通常來講,有兩種響應方式

 注意:通常來講安裝完整項目,內部已經安裝了@types/express這個模塊了

import { Controller, Get, Req, Res, Query, Ip, HttpStatus, Param, Header, Post, Body, UploadedFile } from '@nestjs/common'; import { AppService } from './app.service'; import { Request, Response } from 'express' @Controller('user') //前綴是/user
export class AppController { // 只需要在構造函數里聲明依賴,IOC窗容器會自動幫你注入實例,你直接調用就可以了
 constructor(private readonly appService: AppService) {} @Get() //表示的是/user的響應, 控制器里面一般只用於接收參數,返回響應,並不會真正處理業務
 getHello(): string { return this.appService.getHello(); } @Get('api')  // 訪問的/user/api的路徑進行響應的
  getApi(@Req() request: Request, @Res() response: Response, @Query('age') query: string): any { response.status(HttpStatus.OK).json({ ...request.query, query }) } @Get('ip')  // 獲取ip
 getIp(@Req() request: Request, @Ip() ip ) { return [request.ip, ip] } @Get('header') // 獲取host相關的信息
  @Header('token', '123') getHeader(@Req() request: Request) { return [request.headers, request.header('token')] // 這個是一個對象,如果是request,header則是一個方法
 } @Get('param/:id') // 或者使用:id
  getParams(@Param('id') id: string) { return id; } @Post('param') getPost(@Req() request: Request, @Body() body, @UploadedFile() files) { return [request.method, request.body, body, files] } }

注意:如果引入了@Res() 那么return 將不起作用,需要用response.json或response.send進行返回,但是對於模板的渲染還是按原有方法操作

注意:路由跳轉在response里面,  response.redirect('/test')表示跳轉到路由下 

5、配置靜態資源

文檔地址: https://docs.nestjs.com/techniques/mvc

import { NestFactory } from '@nestjs/core'; import { NestExpressApplication } from '@nestjs/platform-express'; import { AppModule } from './app.module'; import {join} from 'path' async function bootstrap() { const app = await NestFactory.create<NestExpressApplication>(AppModule); //寫法一 // app.useStaticAssets('public') //沒有配置虛擬路徑 訪問目錄 http://localhost:3000/資源名稱 //寫法二 app.useStaticAssets('public', { //設置虛擬路徑 那么訪問的時候就需要用 http://localhost:3000/static/資源名稱 prefix: '/static/' }) //寫法三 // app.useStaticAssets(join(__dirname, '..', 'public'),{ // 注意該寫法與上面寫法是一樣的效果 // prefix: '/static/',  // });
 await app.listen(3000); } bootstrap();

注意:以上是main.ts入口文件,注意__dirname是指在項目下的dist文件,所以在指定路徑的時候,需要注意指向

 6、配置模板引擎

在nest.js中使用的是hbs模板引擎,但是這邊使用的是ejs那么需要配置這個模板引擎

npm i ejs --save

把模板引擎配置到入口文件中

app.setBaseViewsDir(join(__dirname, '..', 'views')) // 放視圖的文件
app.setViewEngine('ejs'); // 指定模板引擎

注意:上述代碼指定了視圖的根目錄為views文件夾下,引擎是ejs, 這就需要在根目錄下創建views,渲染的時候會自動讀取views文件夾下的文件

import { Controller, Get, Render } from '@nestjs/common'; import { AppService } from './app.service'; @Controller() export class AppController { ... @Get('test') @Render('test/index') //指定的是views下test文件下的index.ejs文件
  public testInfo(): {[key: string]: string|number} { return {name: 'ven', age: 20, img: '/static/6.jpg'} //返回需要渲染的數據
 } ... }

具體的ejs的使用可以參看ejs的官方文檔

7、nest.js中的服務

Nestjs 中的服務可以是 service 也可以是 provider。他們都可以通過 constructor 注 入依賴關系。服務本質上就是通過@Injectable() 裝飾器注解的類。在 Nestjs 中服務相 當於 MVC 的 Model。 

服務的創建

nest g service 服務名 (推薦) nest g provider 服務名 幫助信息 nest g --help 
import { Injectable } from '@nestjs/common'; @Injectable() export class YfService { getAll() { return ['aa', 'bb', 'cc'] } }

注意:系統自動生成服務后,會在app.module.ts中的providers中自動引入 ,如果沒有自動引用,則需要手動引入

import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { YfController } from './yf/yf.controller'; import { AppService } from './app.service'; import { YfService } from './yf/yf.service'; @Module({ imports: [], controllers: [AppController, YfController], providers: [AppService, YfService], }) export class AppModule {}

那么如果在需要在controller中使用,也需要進行聲明

import { Controller, Get } from '@nestjs/common'; import { YfService } from './yf.service'; @Controller('yf') export class YfController {  public constructor(private yfservice: YfService) {} @Get() public index() { return this.yfservice.getAll() } }

8、nest中cookie的使用

NestJs 中使用 Cookie 的話我們可以用 cookie-parser來實現 文檔位置: https://docs.nestjs.com/techniques/cookies

安裝

npm i cookie-parser npm i -D @types/cookie-parser

引入到main.ts中

import * as cookieParser from 'cookie-parser';
app.use(cookieParser('加密字符串')); //如果需要加密,則需要配置加密字符串,建議配置,配置后可使用加密狀態也可以不使用加密

controller中的使用

import { Controller, Get, Req, Res } from '@nestjs/common';
import { YfService } from './yf.service';
import { Response, Request } from 'express';

@Controller('yf')
export class YfController {
    public constructor(private yfservice: YfService) {}

    @Get()
    public index(@Res() res: Response) {
        // res.cookie('name', 'this is test name', {maxAge: 90000, httpOnly: true}) =》不加密 //這里設置了過期時間,以及是否只有http訪問 res.cookie('name', 'this is test name', {maxAge: 90000, httpOnly: true, signed: true}) =》 加密
        res.send('this is test')
    }

    @Get('cookie')
    public getCookie(@Req() req: Request): string {
        // return req.cookies.name =》 不加密訪問 // 加密后的cookie訪問 return req.signedCookies.name =》 加密訪問
    }
}

cookie-parser的參數說明

 

domain: 域名

expires : 過 期 時 間 ( 秒 ) , 在 設 置 的 某 個 時 間 點 后 該 Cookie 就 會 失 效 , 如 expires=Wednesday, 09-Nov-99 23:12:40 GMT maxAge: 最大失效時間(毫秒),設置在多少后失效

secure: 當 secure 值為 true 時,cookie 在 HTTP 中是無效,在 HTTPS 中才有效

path: 表示 cookie 影響到的路,如 path=/。如果路徑不能匹配時,瀏覽器則不發送這 個 Cookie

httpOnly:是微軟對 COOKIE 做的擴展。如果在 COOKIE 中設置了“httpOnly”屬性,則通 過程序(JS 腳本、applet 等)將無法讀取到 COOKIE 信息,防止 XSS 攻擊產生

signed : 表 示 是 否 簽 名 cookie, 設 為 true 會 對 這 個 cookie 簽 名 , 這 樣 就 需 要 用 res.signedCookies 而不是 res.cookies 訪問它。被篡改的簽名 cookie 會被服務器拒絕,並且 cookie 值會重置為它的原始值

設置cookie

res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }) res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true }); res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly:true })

獲取cookie

req.cookies.name

刪除cookie

res.cookie('rememberme', '', { expires: new Date(0)}); res.cookie('username','zhangsan',{domain:'.ccc.com',maxAge:0,httpOnly:true});

9、nest.js debugger調試

https://github.com/nestjs/docs.nestjs.com/issues/217

打開界面

在.vscode下的launch.json里配置如下:

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "attach",
      "name": "Attach NestJS WS",
      "port": 9229,
      "restart": true,
      "stopOnEntry": false,
      "protocol": "inspector"
    }
  ]
}

在項目路徑下支行npm run start:debug

在vscode中啟動調試界面

 

 這個時候調用chrome里的inspect監聽9229端口

 

 當代碼運行那指定的debugger的地點時就會啟用斷點,打印指定的變量了

同時也可以點擊下面的界面進行調試

 10、自定義裝飾器

以設置cookie為例封裝一個獲取cookie的裝飾器

import { createParamDecorator, ExecutionContext } from "@nestjs/common"; import { Request } from "express"; export const Cookies = createParamDecorator((data: string, ctx: ExecutionContext) => { // ctx可以獲取到上下文的request和response const request: Request = ctx.switchToHttp().getRequest(); return data? request.signedCookies?.[data]: request.signedCookies; })

這樣就可以在controller中進行使用了

import { Controller, Get, Res  } from '@nestjs/common';
import { Response } from 'express';
import { Cookies } from 'src/utils/decorators';
import { YfService } from './yf.service';

@Controller('yf')
export class YfController {
    public constructor(private yfservice: YfService) {}

    @Get()
    public index(@Res() res: Response) {
        res.cookie('name', 'this is test name', {maxAge: 90000, httpOnly: true, signed: true})
        res.send('this is test')
    }

    @Get('cookie')
    public getCookie(@Cookies('name') data): string {
        return data;
    }
}

 裝飾器嵌套

import { applyDecorators } from '@nestjs/common'; export function Auth(...roles: Role[]) { return applyDecorators( SetMetadata('roles', roles), UseGuards(AuthGuard, RolesGuard), ApiBearerAuth(), ApiUnauthorizedResponse({ description: 'Unauthorized' }), ); }

 使用

@Get('users') @Auth('admin') findAllUsers() {}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM