Nestjs微服务

本文介绍了一种简单的调用微服务方式,适用于快速开发nestjs微服务模块

nestjs的微服务可以类似于springboot,你可以启动多个app分别监听不同的端口

比如localhost:3000是微服务1,localhost:3001是微服务2,每个app都是通过NestFactory.create创建的

但是有的微服务模块供内部调用,而直接通过post和get请求是无法直接调用此模块的,这种模块就是内部调用的微服务模块

具体文档参考nestjs官网 Documentation | NestJS - A progressive Node.js framework

本文对nestjs官网所说的不全面的地方,以及我踩坑的地方详细说明

首先我们使用nest-cli创建一个新项目

npm i -g @nestjs/cli
nest new yourprojectname

接着选择你喜欢使用的包管理工具,在这里我选择使用npm

创建的文件中,打开src/main.ts,你可以看到如下代码

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

然后我们要创建一个微服务,打开控制台,输入下方代码后,使用你喜欢的包管理器

nest new microservice1

我们创建了一个微服务,然后打开这个文件夹,进入microservice1/src/main.ts,修改为如下代码,

下面解释一下,NestFactory.createMicroservice需要传递两个参数,第一个参数是模块名称,通常是主app模块,第二个参数是一个option对象,这个对象里包含transport属性,指定了此微服务模块通过什么方式通信,第二个属性options指定了微服务模块的host,port等信息,因为本次都是在localhost上,所以只指定了端口

import { NestFactory } from '@nestjs/core';
import { Transport, MicroserviceOptions } from '@nestjs/microservices';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    AppModule,
    {
      transport: Transport.TCP,
      options:{
        port:3001,
      }
    },
  );
  app.listen();
}
bootstrap();

这里声明了一个内部微服务模块,其端口是3001,注意不要跟主app和其他微服务端口冲突!使用TCP进行通信,注意,微服务模块不能直接使用get和post请求,而是使用了'pattern'的方式来进行与其他微服务模块之间的相互调用,每个微服务接口都有一个pattern,其他微服务通过触发这个pattern来进行通信,pattern有两种@MessagePattern和@EventPattern,都是在@nestjs/microservices包中导入的,MessagePattern通常用于请求-响应,而EventPattern常常用于接收事件,在本次演示中,我们需要响应请求,所以使用了@MessagePattern

如下代码在microservice1/src/app.controller.ts,我们创建了一个简单的微服务接口,注意我们需要在当前的microservice1模块中安装@nestjs/microservices依赖

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { MessagePattern } from '@nestjs/microservices';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @MessagePattern('math:wordcount')
  wordCount(s: string): string {
    console.log('hello world')
    return '这是math微服务!';
  }
}

接下来我们可以启动这个微服务了!将控制台目录进入到microservice1的目录下,输入

npm run start:dev

启动我们的微服务模块,但是注意这个微服务模块还不能通过postman直接调用

然后我们在我们的主app应用中注册这个微服务,打开外面的yourprojectname/src/app.module.ts,

注意安装@nestjs/microservices包后,通过ClientsModule.register来注册一个或者多个微服务,其参数是一个数组,在每个对象中配置微服务的名称,微服务的通信方式(本次使用TCP),微服务的端口号,这样在我们的主app中我们就可以找到这个微服务并进行通信了!如果微服务模块不在本机上,还需要指定微服务模块的host,这样才能准确定位微服务模块的位置并成功与其通信

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ClientsModule, Transport } from '@nestjs/microservices'; // 注册一个用于对微服务进行数据传输的客户端

@Module({
  imports: [
    ClientsModule.register([
      {
        name: 'MATH_SERVICE',
        transport: Transport.TCP,
        options: {
          port: 3001,
        },
      },
    ]),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

我们通过依赖注入的方式来使用微服务,在yourprojectname/src/app.controller.ts

在其构造函数中注入微服务客户端,这里通过我们注册微服务的名称来选择使用哪个微服务客户端,然后通过这个对象来进行与微服务的通信

import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';
import { ClientProxy } from '@nestjs/microservices';
import { Observable } from 'rxjs';

@Controller()
export class AppController {
  constructor(
    private readonly appService: AppService,
    @Inject('MATH_SERVICE') private client: ClientProxy,
  ) {}

  
  @Get('/ms')
  getHello(): any{
    console.log('调用微服务!')
    return this.client.send('math:wordcount', '');
    
  }
}

这里我们有两种方式与微服务通信,this.client.send和this.client.emit,前者是通过请求-响应的方式,后者是通过事件驱动的方式,这两个的区别是,当我们需要有响应的时候,我们采用send方法,其对应微服务controller中的@MessagePattern,而emit方法表示我们要触发什么事件,对应@EventPattern,而后者通常不需要响应的返回值,只起到通知的作用.

好了,现在我们已经全部定义完了,启动我们的主服务,在根工作目录下输入如下命令:

npm run start:dev

下面打开postman,使用get请求localhost:3000/ms,我们可以得到响应:这是math微服务!

总结一下nestjs的微服务创建流程:

1.创建主app模块

2.创建微服务模块,修改其main.ts,让app成为被createMicroservice创建的,注意端口不要冲突

3.在主app中的module中注册子微服务

4.在主app中的controller或者service中依赖注入微服务客户端,使用send(请求响应)和emit(事件发布)与微服务的controller进行通信

加餐:在上面第3和第4是不是很麻烦,又要在主应用的module中注册,然后才能在service或者controller中注入才行,有一个简单的办法!

以前我们都是使用构造函数注入的,我们可以有一种更简单的注入方式!

我们可以直接通过@Client装饰器注入,这个装饰器填的内容跟在module中使用ClientsModule.register注册的一模一样!,这样我们就不用写在module中了,这样的好处就是方便使用,当我们微服务模块比较少的时候,这样写非常简单,但是注意!当我们微服务模块很多的时候,官方并不推荐我们使用这样的方法,因为它更难测试,也更难共享客户端实例,只有在微服务模块比较少的时候才会使用这种方法,而当我们微服务模块比较多的时候,推荐使用写在module中的imports中使用ClientsModule.register统一注册管理!

import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';
import { ClientProxy, Client, Transport } from '@nestjs/microservices';
import { Observable } from 'rxjs';

@Controller()
export class AppController {

  @Client({ transport: Transport.TCP, options: { port: 3001 } })
  private client: ClientProxy;

  constructor(
    private readonly appService: AppService,
  ) // @Inject('MATH_SERVICE') private client: ClientProxy,
  {}

  @Get('/ms')
  getHello():Observable<any> {
    console.log('调用math微服务!');
    return this.client.send('math:wordcount', '');
  }
}

后续将会更新:Nestjs微服务项目已经开发完毕了,那么应该怎么上线呢?我们将使用docker来将微服务通过dockerfile打包成一个镜像,然后通过docker-compose的方式进行项目部署

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值