NestJS+Prisma开发gRPC服务时Proto文件空返回处理问题
问题核心原因
gRPC 规范不允许 RPC 方法直接返回 null 作为完整响应体,你之前给 UserResponse 内部字段加 optional 仅支持单个字段为空,无法解决整个响应体为空的场景。你定义的 NullableUserResponse 本身没问题,未生效是三个遗漏点导致的:
- 未导入 Google 官方的空值定义依赖
- 未将
findOne方法的返回值替换为自定义的可空类型 - 服务端返回数据未匹配
oneof要求的结构
正确实现步骤
第一步:修改 proto 文件
syntax = "proto3"; package users; // 新增:导入Google官方空值定义 import "google/protobuf/struct.proto"; service UsersService { rpc create (UserRequest) returns (UserResponse) {} rpc findAll (Empty) returns (UsersResponse) {} // 修改:将findOne返回值替换为可空类型 rpc findOne (UserId) returns (NullableUserResponse) {} rpc update (UserRequest) returns (UserResponse) {} rpc remove (UserId) returns (RequestResponse) {} } // 原有其他message定义保持不变 message Empty {} message UserId { string id = 1; } message RequestResponse { string msg = 1; } message UserRequest { string id = 1; string email = 2; string password = 3; enum Status { INACTIVE = 1; ACTIVE = 2; BLOCKED = 3; DELETED = 4; } Status status = 4; } message UserResponse { optional string id = 1; optional string email = 2; optional string password = 3; enum Status { INACTIVE = 1; ACTIVE = 2; BLOCKED = 3; DELETED = 4; } optional Status status = 4; optional string createdAt = 5; optional string updatedAt = 6; } message UsersResponse { repeated UserResponse users = 1; } message Profile { string id = 1; string userId = 2; string name = 3; string birthdate = 4; string tin = 5; string photo = 6; string phone = 7; } // 定义可空用户响应 message NullableUserResponse { oneof kind { google.protobuf.NullValue null = 1; UserResponse data = 2; } }
第二步:修改 NestJS 服务端返回逻辑
Prisma 查询后不能直接返回 null 或者用户对象,需要匹配 NullableUserResponse 的结构:
import { NullValue } from './your-proto-generated-types'; // 从proto生成的TS类型中导入NullValue async findOne(userId: UserId) { const user = await this.prisma.user.findUnique({ where: { id: userId.id } }); if (!user) { // 用户不存在时返回空值结构 return { null: NullValue.NULL_VALUE }; } // 用户存在时返回data结构 return { data: user }; }
第三步:客户端消费逻辑调整
客户端收到响应后先判断返回类型即可:
const userRes = await usersServiceClient.findOne({ id: 'xxx' }).toPromise(); if (userRes.kind === 'null') { // 处理用户不存在的逻辑 } else { const user = userRes.data; // 处理正常用户逻辑 }
可选替代方案
如果你的业务场景中「用户不存在」属于异常情况,也可以直接返回 gRPC 标准错误码,不需要修改 proto 定义,更符合 gRPC 常规设计规范:
import { status } from '@grpc/grpc-js'; import { RpcException } from '@nestjs/microservices'; async findOne(userId: UserId) { const user = await this.prisma.user.findUnique({ where: { id: userId.id } }); if (!user) { throw new RpcException({ code: status.NOT_FOUND, message: '用户不存在' }); } return user; }
内容的提问来源于stack exchange,提问作者Seta-san
相关产品推荐
相关产品推荐

