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;
createUser(data: { name: string; email: string }): Observable;
}
@Injectable()
export class UserService implements OnModuleInit {
private userService: UserServiceClient;
constructor(@Inject('USER_PACKAGE') private client: ClientGrpc) {}
onModuleInit() {
this.userService = this.client.getService('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;
createOrder(data: { userId: string; productIds: string[] }): Observable;
}
@Injectable()
export class OrderService implements OnModuleInit {
private orderService: OrderServiceClient;
constructor(@Inject('ORDER_PACKAGE') private client: ClientGrpc) {}
onModuleInit() {
this.orderService = this.client.getService('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();
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 服务的接口,并根据项目需求选择合适的配置方案。

浙公网安备 33010602011771号