You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 19:00:23