Spring Boot gRpc调用报错:UNAVAILABLE: Network closed for unknown reason
问题描述
客户端接收HTTP GET请求后通过gRPC调用服务端时,触发错误:
io.grpc.StatusRuntimeException: UNAVAILABLE: Network closed for unknown reason
相关代码
Proto文件
syntax = "proto3"; package com.example; option java_multiple_files = true; message Hello{ string message = 1; } message Greet{ string message = 1; } service Greeting { rpc greeting(Hello) returns (Greet){} }
服务端实现
@Service @Slf4j public class GreetingService extends GreetingGrpc.GreetingImplBase { @Override public void greeting(Hello request, StreamObserver<Greet> responseObserver) { log.info("I receive message : " + request); Greet grret = Greet.newBuilder() .setMessage("Hello to you too!") .build(); responseObserver.onNext(grret); responseObserver.onCompleted(); } }
客户端控制器
@RestController @RequestMapping("/api") public class GreetingController { @GetMapping public void greeting(){ ManagedChannel channel = ManagedChannelBuilder .forAddress("localhost", 9000) .usePlaintext().build(); GreetingGrpc.GreetingBlockingStub stub = GreetingGrpc.newBlockingStub(channel); Greet greet = stub.greeting(Hello.newBuilder() .setMessage("Hello, World!") .build()); channel.shutdown(); } }
pom.xml(服务端/客户端)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.0.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>server</artifactId> <version>0.0.1-SNAPSHOT</version> <name>server</name> <description>server</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>1.16.1</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.16.1</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.16.1</version> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.2</version> </dependency> </dependencies> <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.6.1</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.6.1</version> <configuration> <protocArtifact> com.google.protobuf:protoc:3.3.0:exe:${os.detected.classifier} </protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact> io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier} </pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
解决方案
1. 启动服务端gRPC监听
当前服务端仅实现了gRPC服务类,但未启动gRPC服务器监听9000端口。添加启动代码:
@SpringBootApplication public class ServerApplication { public static void main(String[] args) { SpringApplication.run(ServerApplication.class, args); // 启动gRPC服务器 try { Server server = ServerBuilder.forPort(9000) .addService(new GreetingService()) .build() .start(); System.out.println("gRPC server started on port 9000"); server.awaitTermination(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
2. 修复依赖版本冲突
Spring Boot 3.0.5(Java 17)与gRPC 1.16.1版本不兼容,且老版本gRPC依赖的javax.annotation-api与Spring Boot 3的Jakarta API冲突。更新依赖:
<dependencies> <!-- 替换为兼容的gRPC版本 --> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> <version>1.59.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.59.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.59.0</version> </dependency> <!-- 替换javax为Jakarta注解 --> <dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> <version>2.1.1</version> </dependency> </dependencies>
同时更新protobuf插件版本,确保与gRPC匹配:
<build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.7.0</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.6.1</version> <configuration> <protocArtifact> com.google.protobuf:protoc:3.24.4:exe:${os.detected.classifier} </protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact> io.grpc:protoc-gen-grpc-java:1.59.0:exe:${os.detected.classifier} </pluginArtifact> </configuration> </plugin> </plugins> </build>
3. 优化客户端通道管理
避免每次请求创建新通道,将ManagedChannel配置为单例,并在应用关闭时正确关闭:
@RestController @RequestMapping("/api") public class GreetingController { private final ManagedChannel channel; private final GreetingGrpc.GreetingBlockingStub stub; public GreetingController() { this.channel = ManagedChannelBuilder .forAddress("localhost", 9000) .usePlaintext() .build(); this.stub = GreetingGrpc.newBlockingStub(channel); } @GetMapping public String greeting(){ Greet greet = stub.greeting(Hello.newBuilder() .setMessage("Hello, World!") .build()); return greet.getMessage(); } @PreDestroy public void shutdown() { channel.shutdown(); try { if (!channel.awaitTermination(5, TimeUnit.SECONDS)) { channel.shutdownNow(); } } catch (InterruptedException e) { channel.shutdownNow(); } } }
4. 检查端口状态
用netstat -ano(Windows)或lsof -i :9000(Linux/Mac)确认9000端口未被其他程序占用,且服务端与客户端使用的端口一致。
内容的提问来源于stack exchange,提问作者therepanic
相关产品推荐
相关产品推荐

