Spring Boot中RSocket与gRPC结合的Proto解码异常求助
你遇到的No decoder for me.some.protoapi.ValidationTaskResponse异常,核心原因是RSocket默认的编解码器集合里没有包含Protobuf的处理逻辑,再加上代码里还有几个小细节需要调整,下面一步步帮你解决:
1. 补全必要的依赖
首先确保项目引入了Protobuf和RSocket适配的核心依赖,如果是Maven,在pom.xml中添加:
<!-- RSocket核心依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-rsocket</artifactId> </dependency> <!-- Protobuf Java支持 --> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.24.4</version> <!-- 选择与protoc版本匹配的版本 --> </dependency> <!-- WebFlux(提供Protobuf编解码器) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
Gradle用户可以用如下配置:
implementation 'org.springframework.boot:spring-boot-starter-rsocket' implementation 'com.google.protobuf:protobuf-java:3.24.4' implementation 'org.springframework.boot:spring-boot-starter-webflux'
2. 配置RSocket的Protobuf编解码器
你原来的RSocketConfiguration使用了默认的RSocketStrategies,它不包含Protobuf编解码逻辑,需要自定义该Bean并添加对应的编码器和解码器:
@Configuration public class RSocketConfiguration { @Bean public RSocket rSocket(@Value("${rsocket.client.port}") int port) { return RSocketFactory .connect() // 替换ALL_VALUE为Protobuf专属MIME类型,明确传输格式 .mimeType(MediaType.APPLICATION_PROTOBUF_VALUE, MediaType.APPLICATION_PROTOBUF_VALUE) .frameDecoder(PayloadDecoder.ZERO_COPY) .transport(TcpClientTransport.create(port)) .start() .retry() .block(); } // 自定义RSocketStrategies,注入Protobuf编解码器 @Bean public RSocketStrategies rSocketStrategies() { return RSocketStrategies.builder() .encoder(new ProtobufEncoder()) .decoder(new ProtobufDecoder()) .build(); } @Bean public RSocketRequester rSocketRequester(RSocket rSocket, RSocketStrategies rSocketStrategies) { return RSocketRequester.wrap( rSocket, MediaType.APPLICATION_PROTOBUF, // 明确指定Protobuf格式 MediaType.APPLICATION_PROTOBUF, rSocketStrategies ); } }
这里的关键调整:
- 替换
MimeTypeUtils.ALL_VALUE为MediaType.APPLICATION_PROTOBUF,避免RSocket因格式模糊无法选择编解码器 - 给
RSocketStrategies添加ProtobufEncoder和ProtobufDecoder,让RSocket具备处理Protobuf消息的能力
3. 修复请求数据的构建问题
你的requestValidation方法中,传递的是ValidationTaskRequest.Builder对象,而非最终构建完成的ValidationTaskRequest实例,RSocket无法识别Builder类型,必须调用.build()生成实际消息:
private Mono<ValidationTaskResponse> requestValidation(Task task) { return rSocketRequester .route(rSocketValidationRoute) .data( ValidationTaskRequest .newBuilder() .setId(task.getId()) .setName(task.getName()) .build() // 必须调用build()生成消息实例 ) .retrieveMono(ValidationTaskResponse.class); }
4. 确保服务端同步配置编解码器
如果你的RSocket服务端是自行开发的,别忘了在服务端配置中也添加Protobuf编解码器,否则服务端无法解码请求、编码响应:
@Configuration public class RSocketServerConfig { @Bean public RSocketServerCustomizer rSocketServerCustomizer() { return server -> server .rsocketStrategies(strategies -> strategies .encoder(new ProtobufEncoder()) .decoder(new ProtobufDecoder())); } }
最后验证Protobuf代码生成
确认你的Protobuf插件(比如Maven的protobuf-maven-plugin)已正确配置,编译时能自动生成ValidationTaskRequest、ValidationTaskResponse等Java类,这是后续编解码的基础。
按照以上步骤调整后,RSocket就能正确识别并编解码你的Protobuf消息,应该可以解决解码器不存在的异常。
内容的提问来源于stack exchange,提问作者Scrobot

