iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 5
1
Modern Web

Nest.js framework 30天初探系列 第 5

Nestjs framework 30天初探:Day05 Middlewares

Middlewares

https://ithelp.ithome.com.tw/upload/images/20171207/201071954tc8kd4boV.png

Middlewares相信用Express框架開發的朋友對這名詞不會太陌生,很多時候我們會透過Middlewares,在router收到請求前就先做些處理,Nestjs在這方面有不少的著墨,可以讓我們在使用Middlewares時有更細緻的處理。

  1. 接下來開始我們coding時間,新增Shared/middlewares,下cmd指令。
cd src/modules & mkdir Shared & cd Shared & mkdir Middlewares
  1. 新增logger.middleware.ts,並寫些程式,程式碼如下:
    src/modules/Shared/Middlewares/logger.middleware.ts
import { Middleware, ExpressMiddleware, NestMiddleware } from '@nestjs/common';

//Middleware的裝飾器
@Middleware()
export class LoggerMiddleware implements NestMiddleware {
    //resolve可以傳參
    resolve(...args: any[]): ExpressMiddleware {
        //會返回ExpressMiddleware
        return (req, res, next) => {
            console.log('執行middleware...');
            //呼叫next()方法,程式才會繼續往下執行,否則將停在此階段。
            next();
        }
    }
}

核心概念其實跟Express的Middleware相差無幾。

  1. 接著在ApplicationModule使用LoggerMiddleware,這跟Components和Modules的概念不太一樣,是使用在根模組,程式碼如下。
    src/modules/app.module.ts
import { Module, RequestMethod } from '@nestjs/common';
import { UsersService } from './Users/Services/users.service';
import { UsersModule } from './Users/users.module';
import { LoggerMiddleware } from './Shared/Middlewares/logger.middleware';
import { NestModule, MiddlewaresConsumer } from '@nestjs/common/interfaces';

@Module({
  modules: [UsersModule]
})
//NestModule本身是個Interface,建議要implements。 
export class ApplicationModule  implements NestModule{
  configure(consumer: MiddlewaresConsumer): void {
    //apply、forRoute方法允許傳入多個參數
    consumer.apply(LoggerMiddleware).forRoutes(
      //RequestMethod有多個HTTP Method的屬性可以使用
      { path: '/users', method: RequestMethod.ALL },
      { path: '/products', method: RequestMethod.ALL }
    )
  }
}
  1. 接著打開Postman,對http://localhost:3000/products 進行GET請求,console結果如下。
[Nest] 15480   - 2017-12-7 23:21:06   [NestFactory] Starting Nest application...
[Nest] 15480   - 2017-12-7 23:21:06   [InstanceLoader] ApplicationModule dependencies initialized +7ms
[Nest] 15480   - 2017-12-7 23:21:06   [InstanceLoader] UsersModule dependencies initialized +3ms
[Nest] 15480   - 2017-12-7 23:21:06   [InstanceLoader] ProductsModule dependencies initialized +2ms
[Nest] 15480   - 2017-12-7 23:21:06   [RoutesResolver] UsersController {/}: +53ms
[Nest] 15480   - 2017-12-7 23:21:06   [RouterExplorer] Mapped {/users, GET} route +3ms
[Nest] 15480   - 2017-12-7 23:21:06   [RouterExplorer] Mapped {/users/:id, GET} route +1ms
[Nest] 15480   - 2017-12-7 23:21:06   [RouterExplorer] Mapped {/users, POST} route +1ms
[Nest] 15480   - 2017-12-7 23:21:06   [RouterExplorer] Mapped {/testProducts, GET} route +1ms
[Nest] 15480   - 2017-12-7 23:21:06   [RoutesResolver] ProductsController {/products}: +2ms
[Nest] 15480   - 2017-12-7 23:21:06   [RouterExplorer] Mapped {/, GET} route +10ms
[Nest] 15480   - 2017-12-7 23:21:06   [RouterExplorer] Mapped {/:id, GET} route +2ms
[Nest] 15480   - 2017-12-7 23:21:06   [RouterExplorer] Mapped {/, POST} route +1ms
[Nest] 15480   - 2017-12-7 23:21:06   [NestApplication] Nest application successfully started +3ms
Application based on Express is listening on port 3000
執行middleware...

LoggerMiddleware有正常執行。

  1. 要在forRoutes寫一堆路徑和HTTP方法很累人,Nestjs允許傳入Controller,修改程式碼如下。
    src/modules/app.module.ts
import { Module, RequestMethod } from '@nestjs/common';
import { UsersController } from './Users/users.controller';
import { UsersService } from './Users/Services/users.service';
import { UsersModule } from './Users/users.module';
import { LoggerMiddleware } from './Shared/Middlewares/logger.middleware';
import { NestModule, MiddlewaresConsumer } from '@nestjs/common/interfaces';
import { ProductsController } from './Products/products.controller';

@Module({
  modules: [UsersModule]
})
//NestModule本身是個Interface,建議要implements。
export class ApplicationModule  implements NestModule{
  configure(consumer: MiddlewaresConsumer): void {
    //apply、forRoute方法允許傳入多個參數
    consumer.apply(LoggerMiddleware).forRoutes(
      //load進Controllers
      UsersController,
      ProductsController
    )
  }
}
  1. nestjs甚至允許你從根模組傳入參數到Middleware,程式碼如下。
    src/modules/app.module.ts
import { Module, RequestMethod } from '@nestjs/common';
import { UsersController } from './Users/users.controller';
import { UsersService } from './Users/Services/users.service';
import { UsersModule } from './Users/users.module';
import { LoggerMiddleware } from './Shared/Middlewares/logger.middleware';
import { NestModule, MiddlewaresConsumer } from '@nestjs/common/interfaces';
import { ProductsController } from './Products/products.controller';

@Module({
  modules: [UsersModule]
})
//NestModule本身是個Interface,建議要implements。
export class ApplicationModule  implements NestModule{
  configure(consumer: MiddlewaresConsumer): void {
    //apply、forRoute方法允許傳入多個參數
    consumer.apply(LoggerMiddleware)
    //with方法可以傳入參數到middleware
    .with('來自根模組的參數')
    .forRoutes(
      //load進Controllers
      UsersController,
      ProductsController
    )
  }
}

src/modules/Shared/Middlewares/logger.middleware.ts

import { Middleware, ExpressMiddleware, NestMiddleware } from '@nestjs/common';

//Middleware的裝飾器
@Middleware()
export class LoggerMiddleware implements NestMiddleware {
    //resolve可以傳參
    resolve(message: string): ExpressMiddleware {
        //會返回ExpressMiddleware
        return (req, res, next) => {
            //使用字符串
            console.log(`${message}`);
            console.log('執行middleware...');
            //呼叫next()方法,程式才會繼續往下執行,否則將停在此階段。
            next();
        }
    }
}

console結果如下。

[Nest] 13708   - 2017-12-7 23:47:52   [NestFactory] Starting Nest application...                        
[Nest] 13708   - 2017-12-7 23:47:52   [InstanceLoader] ApplicationModule dependencies initialized +7ms  
[Nest] 13708   - 2017-12-7 23:47:52   [InstanceLoader] UsersModule dependencies initialized +4ms        
[Nest] 13708   - 2017-12-7 23:47:52   [InstanceLoader] ProductsModule dependencies initialized +1ms     
[Nest] 13708   - 2017-12-7 23:47:52   [RoutesResolver] UsersController {/}: +55ms                       
[Nest] 13708   - 2017-12-7 23:47:52   [RouterExplorer] Mapped {/users, GET} route +3ms                  
[Nest] 13708   - 2017-12-7 23:47:52   [RouterExplorer] Mapped {/users/:id, GET} route +1ms              
[Nest] 13708   - 2017-12-7 23:47:52   [RouterExplorer] Mapped {/users, POST} route +1ms                 
[Nest] 13708   - 2017-12-7 23:47:52   [RouterExplorer] Mapped {/testProducts, GET} route +1ms           
[Nest] 13708   - 2017-12-7 23:47:52   [RoutesResolver] ProductsController {/products}: +1ms             
[Nest] 13708   - 2017-12-7 23:47:52   [RouterExplorer] Mapped {/, GET} route +3ms                       
[Nest] 13708   - 2017-12-7 23:47:52   [RouterExplorer] Mapped {/:id, GET} route +3ms                    
[Nest] 13708   - 2017-12-7 23:47:52   [RouterExplorer] Mapped {/, POST} route +8ms                      
[Nest] 13708   - 2017-12-7 23:47:52   [NestApplication] Nest application successfully started +2ms      
Application based on Express is listening on port 3000                                                  
來自根模組的參數                                                                                                
執行middleware...                                                                                         

middleware確實有收到來自根模組傳過來的參數。

  1. 我們也可以寫單純的function作為Middleware,新增simple.middleware.ts,程式碼如下。
    src/modules/Shared/Middlewares/simple.middleware.ts
export const SimpleMiddleware = (req, res, next) => {
    console.log('我是簡單的Middleware');
    next();
}
  1. 修改ApplicationModule,加入SimpleMiddleware,程式碼如下。
import { Module, RequestMethod } from '@nestjs/common';
import { UsersController } from './Users/users.controller';
import { UsersService } from './Users/Services/users.service';
import { UsersModule } from './Users/users.module';
import { LoggerMiddleware } from './Shared/Middlewares/logger.middleware';
import { SimpleMiddleware } from './Shared/Middlewares/simple.middleware';
import { NestModule, MiddlewaresConsumer } from '@nestjs/common/interfaces';
import { ProductsController } from './Products/products.controller';

@Module({
  modules: [UsersModule]
})
//NestModule本身是個Interface,建議要implements。
export class ApplicationModule implements NestModule {
  configure(consumer: MiddlewaresConsumer): void {
    //apply、forRoute方法允許傳入多個參數
    consumer.apply([LoggerMiddleware,SimpleMiddleware])
      //with方法可以傳入參數到middleware
      .with('來自根模組的參數')
      .forRoutes(
      //load進Controllers
      UsersController,
      ProductsController
      )
  }
}
  1. 大功告成,觀察到console畫面,LoggerMiddleware和SimpleMiddleware都有正常執行。
    console畫面

[Nest] 7232   - 2017-12-8 00:30:29   [NestFactory] Starting Nest application...
[Nest] 7232   - 2017-12-8 00:30:29   [InstanceLoader] ApplicationModule dependencies initialized +7ms
[Nest] 7232   - 2017-12-8 00:30:29   [InstanceLoader] UsersModule dependencies initialized +2ms
[Nest] 7232   - 2017-12-8 00:30:29   [InstanceLoader] ProductsModule dependencies initialized +1ms
[Nest] 7232   - 2017-12-8 00:30:30   [RoutesResolver] UsersController {/}: +66ms
[Nest] 7232   - 2017-12-8 00:30:30   [RouterExplorer] Mapped {/users, GET} route +4ms
[Nest] 7232   - 2017-12-8 00:30:30   [RouterExplorer] Mapped {/users/:id, GET} route +1ms
[Nest] 7232   - 2017-12-8 00:30:30   [RouterExplorer] Mapped {/users, POST} route +1ms
[Nest] 7232   - 2017-12-8 00:30:30   [RouterExplorer] Mapped {/testProducts, GET} route +1ms
[Nest] 7232   - 2017-12-8 00:30:30   [RoutesResolver] ProductsController {/products}: +1ms
[Nest] 7232   - 2017-12-8 00:30:30   [RouterExplorer] Mapped {/, GET} route +1ms
[Nest] 7232   - 2017-12-8 00:30:30   [RouterExplorer] Mapped {/:id, GET} route +1ms
[Nest] 7232   - 2017-12-8 00:30:30   [RouterExplorer] Mapped {/, POST} route +0ms
[Nest] 7232   - 2017-12-8 00:30:30   [NestApplication] Nest application successfully started +3ms
Application based on Express is listening on port 3000
來自根模組的參數
執行middleware...
我是簡單的Middleware

Middlewares執行是有順序性的,consumer.apply([xxx,ooo]),會依據陣列順序下去執行,藉由next()進行下個Middware。

程式在github


上一篇
Nestjs framework 30天初探:Day04 Modules
下一篇
Nestjs framework 30天初探:Day06 Exception Filters
系列文
Nest.js framework 30天初探30

尚未有邦友留言

立即登入留言