nestjs集成grpc服务
h5打开以查看
一、基础配置方法
1. 项目结构准备
text
src/ ├── grpc/ │ ├── user/ │ │ └── user.proto │ ├── order/ │ │ └── order.proto │ └── product/ │ └── product.proto ├── user/ │ ├── user.module.ts │ └── user.service.ts ├── order/ │ ├── order.module.ts │ └── order.service.ts └── product/├── product.module.ts└── product.service.ts
2. 定义多个 Proto 文件
user.proto
protobuf
syntax = "proto3";package user;service UserService {rpc GetUser (UserRequest) returns (UserResponse) {}rpc CreateUser (CreateUserRequest) returns (UserResponse) {}
}message UserRequest {string id = 1;
}message CreateUserRequest {string name = 1;string email = 2;
}message UserResponse {string id = 1;string name = 2;string email = 3;
}
order.proto
protobuf
syntax = "proto3";package order;service OrderService {rpc GetOrder (OrderRequest) returns (OrderResponse) {}rpc CreateOrder (CreateOrderRequest) returns (OrderResponse) {}
}message OrderRequest {string id = 1;
}message CreateOrderRequest {string userId = 1;repeated string productIds = 2;
}message OrderResponse {string id = 1;string userId = 2;repeated string productIds = 3;string status = 4;
}
二、方式一:使用多个微服务客户端(推荐)
1. 配置多个 gRPC 客户端
app.module.ts
typescript
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { join } from 'path';
import { UserModule } from './user/user.module';
import { OrderModule } from './order/order.module';@Module({imports: [ClientsModule.register([// 用户服务 gRPC 客户端{name: 'USER_PACKAGE',transport: Transport.GRPC,options: {package: 'user',protoPath: join(__dirname, 'grpc/user/user.proto'),url: 'localhost:50051', // 用户服务地址},},// 订单服务 gRPC 客户端{name: 'ORDER_PACKAGE',transport: Transport.GRPC,options: {package: 'order',protoPath: join(__dirname, 'grpc/order/order.proto'),url: 'localhost:50052', // 订单服务地址},},]),UserModule,OrderModule,],
})
export class AppModule {}
2. 创建用户服务
user/user.service.ts
typescript
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { Observable } from 'rxjs';interface UserServiceClient {getUser(data: { id: string }): Observable<any>;createUser(data: { name: string; email: string }): Observable<any>;
}@Injectable()
export class UserService implements OnModuleInit {private userService: UserServiceClient;constructor(@Inject('USER_PACKAGE') private client: ClientGrpc) {}onModuleInit() {this.userService = this.client.getService<UserServiceClient>('UserService');}async getUser(id: string) {return this.userService.getUser({ id });}async createUser(name: string, email: string) {return this.userService.createUser({ name, email });}
}
user/user.module.ts
typescript
import { Module } from '@nestjs/common';
import { UserService } from './user.service';@Module({providers: [UserService],exports: [UserService],
})
export class UserModule {}
3. 创建订单服务
order/order.service.ts
typescript
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { Observable } from 'rxjs';interface OrderServiceClient {getOrder(data: { id: string }): Observable<any>;createOrder(data: { userId: string; productIds: string[] }): Observable<any>;
}@Injectable()
export class OrderService implements OnModuleInit {private orderService: OrderServiceClient;constructor(@Inject('ORDER_PACKAGE') private client: ClientGrpc) {}onModuleInit() {this.orderService = this.client.getService<OrderServiceClient>('OrderService');}async getOrder(id: string) {return this.orderService.getOrder({ id });}async createOrder(userId: string, productIds: string[]) {return this.orderService.createOrder({ userId, productIds });}
}
order/order.module.ts
typescript
import { Module } from '@nestjs/common';
import { OrderService } from './order.service';@Module({providers: [OrderService],exports: [OrderService],
})
export class OrderModule {}
4. 在控制器中使用多个服务
app.controller.ts
typescript
import { Controller, Get, Post, Body, Inject } from '@nestjs/common';
import { UserService } from './user/user.service';
import { OrderService } from './order/order.service';@Controller()
export class AppController {constructor(private readonly userService: UserService,private readonly orderService: OrderService,) {}@Get('user/:id')async getUser(@Param('id') id: string) {return this.userService.getUser(id);}@Post('order')async createOrder(@Body() createOrderDto: { userId: string; productIds: string[] }) {// 先验证用户是否存在const user = await this.userService.getUser(createOrderDto.userId);// 然后创建订单const order = await this.orderService.createOrder(createOrderDto.userId,createOrderDto.productIds,);return {user: user,order: order,};}
}
三、方式二:动态配置多个 gRPC 服务
1. 创建配置工厂
grpc/grpc.config.ts
typescript
import { Transport } from '@nestjs/microservices';
import { join } from 'path';export const grpcClientOptions = {user: {transport: Transport.GRPC,options: {package: 'user',protoPath: join(__dirname, 'user/user.proto'),url: 'localhost:50051',},},order: {transport: Transport.GRPC,options: {package: 'order',protoPath: join(__dirname, 'order/order.proto'),url: 'localhost:50052',},},product: {transport: Transport.GRPC,options: {package: 'product',protoPath: join(__dirname, 'product/product.proto'),url: 'localhost:50053',},},
};
2. 动态模块配置
grpc/grpc.module.ts
typescript
import { DynamicModule, Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices';
import { grpcClientOptions } from './grpc.config';@Module({})
export class GrpcModule {static register(clients: string[]): DynamicModule {const clientConfigs = clients.map(clientName => ({name: clientName.toUpperCase() + '_PACKAGE',...grpcClientOptions[clientName],}));return {module: GrpcModule,imports: [ClientsModule.register(clientConfigs)],exports: [ClientsModule],};}
}
3. 使用动态模块
app.module.ts
typescript
import { Module } from '@nestjs/common';
import { GrpcModule } from './grpc/grpc.module';
import { UserService } from './user/user.service';
import { OrderService } from './order/order.service';@Module({imports: [GrpcModule.register(['user', 'order', 'product']),// ... 其他模块],providers: [UserService, OrderService],
})
export class AppModule {}
四、方式三:使用配置文件和异步注册
1. 配置文件
config/grpc.config.ts
typescript
export default () => ({grpc: {services: {user: {package: 'user',protoPath: 'grpc/user/user.proto',url: process.env.USER_GRPC_URL || 'localhost:50051',},order: {package: 'order',protoPath: 'grpc/order/order.proto',url: process.env.ORDER_GRPC_URL || 'localhost:50052',},product: {package: 'product',protoPath: 'grpc/product/product.proto',url: process.env.PRODUCT_GRPC_URL || 'localhost:50053',},},},
});
2. 异步配置模块
grpc/grpc-client.module.ts
typescript
import { DynamicModule, Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { join } from 'path';@Module({})
export class GrpcClientModule {static forRoot(serviceNames: string[]): DynamicModule {const clients = serviceNames.map(serviceName => ({name: `${serviceName.toUpperCase()}_PACKAGE`,useFactory: (configService: ConfigService) => {const serviceConfig = configService.get(`grpc.services.${serviceName}`);return {transport: Transport.GRPC,options: {package: serviceConfig.package,protoPath: join(__dirname, '..', serviceConfig.protoPath),url: serviceConfig.url,},};},inject: [ConfigService],}));return {module: GrpcClientModule,imports: [ClientsModule.registerAsync(clients),],exports: [ClientsModule],};}
}
3. 在主模块中使用
app.module.ts
typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { GrpcClientModule } from './grpc/grpc-client.module';
import configuration from './config/configuration';@Module({imports: [ConfigModule.forRoot({load: [configuration],}),GrpcClientModule.forRoot(['user', 'order', 'product']),// ... 其他模块],
})
export class AppModule {}
五、统一服务工厂模式
创建统一的 gRPC 服务工厂
grpc/grpc-factory.service.ts
typescript
import { Injectable, Inject, OnModuleInit } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { Observable } from 'rxjs';@Injectable()
export class GrpcServiceFactory implements OnModuleInit {private services = new Map<string, any>();constructor(@Inject('USER_PACKAGE') private userClient: ClientGrpc,@Inject('ORDER_PACKAGE') private orderClient: ClientGrpc,@Inject('PRODUCT_PACKAGE') private productClient: ClientGrpc,) {}onModuleInit() {// 初始化所有服务this.services.set('user', this.userClient.getService('UserService'));this.services.set('order', this.orderClient.getService('OrderService'));this.services.set('product', this.productClient.getService('ProductService'));}getService(serviceName: string) {const service = this.services.get(serviceName);if (!service) {throw new Error(`gRPC service ${serviceName} not found`);}return service;}// 快捷方法getUserService() {return this.getService('user');}getOrderService() {return this.getService('order');}getProductService() {return this.getService('product');}
}
六、最佳实践建议
-
服务发现集成:在生产环境中,建议使用服务发现(如 Consul、Nacos)而不是硬编码 URL
-
连接管理:配置连接池和重试策略
-
错误处理:统一处理 gRPC 错误
-
超时设置:为每个服务设置合理的超时时间
-
健康检查:实现 gRPC 健康检查
typescript
// 示例:带超时和重试的配置
{transport: Transport.GRPC,options: {package: 'user',protoPath: join(__dirname, 'grpc/user/user.proto'),url: 'localhost:50051',maxRetries: 3,timeout: 5000, // 5秒超时keepalive: {keepaliveTimeMs: 30000,keepaliveTimeoutMs: 10000,},},
}
通过以上方式,可以在 NestJS 中灵活地调用多个 gRPC 服务的接口,并根据项目需求选择合适的配置方案。
h5打开以查看
