构建Nestjs微服务

127 阅读2分钟

Nest 支持多种内置的传输层实现,称为传输器,它们负责在不同的微服务实例之间传输消息。大多数传输器本身支持请求-响应和基于事件的消息样式。Nest 将每个传输器的实现细节抽象为请求-响应和基于事件的消息传递的规范接口。

创建项目

使用 cli 创建项目

nest new bookstore

创建微服务

进入目录后,使用 cli 创建微服务

nest g app warehouse

安装微服务和配置的依赖包

pnpm i @nestjs/microservices
pnpm i @nestjs/config

创建 .env 文件,配置微服务的 host 和 port

BOOKSTORE_SERVICE_HOST=127.0.0.1
BOOKSTORE_SERVICE_PORT=3001

设置微服务

修改 warehouse 模块

修改 apps/warehouse/warehouse.module.ts 文件,把config模块引入

import { Module } from '@nestjs/common';
import { WarehouseController } from './warehouse.controller';
import { WarehouseService } from './warehouse.service';
import { ConfigModule } from '@nestjs/config';
 
@Module({
  imports: [ConfigModule.forRoot()],
  controllers: [WarehouseController],
  providers: [WarehouseService],
})
export class WarehouseModule {}

修改 warehouse 主文件

修改 apps/warehouse/main.ts 文件,先创建app上下文,获取到config的配置中微服务的 host 和port 值。使用 createMicroservice 创建微服务,设置TCP传输和参数

import { NestFactory } from '@nestjs/core';
import { WarehouseModule } from './warehouse.module';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { ConfigService } from '@nestjs/config';
 
async function bootstrap() {
  const appContext = await NestFactory.createApplicationContext(
    WarehouseModule,
  );
  const configService = appContext.get(ConfigService);
  const host = configService.get<string>('BOOKSTORE_SERVICE_HOST');
  const port = configService.get<number>('BOOKSTORE_SERVICE_PORT');
 
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    WarehouseModule,
    {
      transport: Transport.TCP,
      options: {
        host: host,
        port: port,
      },
    },
  );
  await app.listen();
}
bootstrap();

修改 warehouse 控制器

增加 addBook 添加图书, getBook 通过ID查询图书, getBooks 查询所有图书,3个方法。并使用 MessagePattern 装饰器,启用请求-响应消息类型。

import { Controller } from '@nestjs/common';
import { WarehouseService } from './warehouse.service';
import { MessagePattern } from '@nestjs/microservices';
import { bookDto } from 'dto/book.dto';
 
@Controller()
export class WarehouseController {
  constructor(private readonly warehouseService: WarehouseService) {}
 
  @MessagePattern({ cmd: 'add_book' })
  addBook(book: bookDto) {
    return this.warehouseService.addBook(book);
  }
 
  @MessagePattern({ cmd: 'get_book' })
  getBook(id: string) {
    return this.warehouseService.getBook(id);
  }
 
  @MessagePattern({ cmd: 'get_books' })
  getBooks() {
    return this.warehouseService.getAllBooks();
  }
}

book.dto.ts 文件

export class bookDto {
  id: string;
  title: string;
  author: string;
  release_date: string;
}

修改 warehouse 服务

import { Injectable } from '@nestjs/common';
import { bookDto } from 'dto/book.dto';
 
const bookStore: bookDto[] = [];
 
@Injectable()
export class WarehouseService {
  addBook(book: bookDto) {
    book.id = bookStore.length + 1 + '';
    bookStore.push(book);
    return book;
  }
 
  getBook(id: string) {
    return bookStore.find((book: bookDto) => book.id === id);
  }
 
  getAllBooks() {
    return bookStore;
  }
}

设置主服务

修改 bookstore 模块

添加 config 模块和微服务的 provide

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ClientProxyFactory, Transport } from '@nestjs/microservices';
 
@Module({
  imports: [ConfigModule.forRoot()],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: 'WAREHOUSE_SERVICE',
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => {
        return ClientProxyFactory.create({
          transport: Transport.TCP,
          options: {
            host: configService.get('BOOKSTORE_SERVICE_HOST'),
            port: configService.get('BOOKSTORE_SERVICE_PORT'),
          },
        });
      },
    },
  ],
})
export class AppModule {}

修改 bookstore 控制器

注入微服务的service,并增加3个方法。getAllBooks 查询所有图书。getBookById 通过ID查询图书。addBook 添加图书

import { Body, Controller, Get, Inject, Param, Post } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { bookDto } from 'dto/book.dto';
import { Observable } from 'rxjs';
 
@Controller('bookstore')
export class AppController {
  constructor(
    @Inject('WAREHOUSE_SERVICE') private warehouseService: ClientProxy,
  ) {}

  @Get()
  getAllBooks(): Observable<bookDto[]> {
    return this.warehouseService.send({ cmd: 'get_books' }, {});
  }

  @Get(':id')
  getBookById(@Param('id') id: string): Observable<bookDto | undefined> {
    return this.warehouseService.send({ cmd: 'get_book' }, id);
  }

  @Post()
  addBook(@Body() book: bookDto): Observable<bookDto> {
    return this.warehouseService.send({ cmd: 'add_book' }, book);
  }
}

启动服务

# 启动微服务
nest start warehouse --watch

# 启动主服务
nest start bookstore --watch

使用postman调用

/*
http://localhost:3000/bookstore
post boday
title: 测试
author: 测试
release_date: 2021-01-01
*/

// http://localhost:3000/bookstore

// http://localhost:3000/bookstore/1