Java调用gRPC遇UNAVAILABLE网络错误的解决方法
你的问题确实是明文客户端连接TLS服务导致的。grpcurl命令中的-insecure参数是启用TLS但跳过服务器证书验证,而非使用明文连接;但你的Java代码使用usePlaintext(),会让客户端以明文方式连接443端口的TLS服务,导致握手失败,出现网络关闭错误。此外,grpcurl中指定的-rpc-header和-authority参数,Java代码也需要对应配置,否则请求可能被网关拒绝。
修改后的Java代码
import io.grpc.CallCredentials; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.Metadata; import io.grpc.StatusRuntimeException; import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; import javax.net.ssl.SSLException; import java.util.concurrent.Executor; try { // 构建TLS通道,跳过证书验证(对应grpcurl的-insecure参数) SslContext sslContext = SslContextBuilder.forClient() .trustManager(InsecureTrustManagerFactory.INSTANCE) .build(); ManagedChannel channel = ManagedChannelBuilder.forAddress("aiplatform-grpc.dev51.cbf.dev.paypalinc.com", 443) .useTransportSecurity() .sslContext(sslContext) // 设置Authority头(对应grpcurl的-authority参数) .defaultAuthority("aiplatform-grpc.dev51.cbf.dev.paypalinc.com") .build(); // 添加自定义RPC请求头(对应grpcurl的-rpc-header参数) PredictionServiceGrpc.PredictionServiceBlockingStub preStub = PredictionServiceGrpc.newBlockingStub(channel) .withCallCredentials(new CallCredentials() { @Override public void applyRequestMetadata(RequestMetadata requestMetadata, Executor executor, MetadataApplier metadataApplier) { executor.execute(() -> { Metadata metadata = new Metadata(); metadata.put(Metadata.Key.of("seldon", Metadata.ASCII_STRING_MARSHALLER), "bmv3"); metadata.put(Metadata.Key.of("namespace", Metadata.ASCII_STRING_MARSHALLER), "seldon"); metadataApplier.apply(metadata); }); } @Override public void thisUsesUnstableApi() {} }); response = preStub.predict(predictReq); } catch (StatusRuntimeException e) { System.out.println("Call gRPC error, e:" + e.getMessage()); return; } catch (SSLException e) { System.out.println("SSL configuration error, e:" + e.getMessage()); return; }
关键修改说明
- 替换明文连接为TLS配置:移除
usePlaintext(),改用useTransportSecurity()启用TLS,并通过InsecureTrustManagerFactory跳过证书验证,和grpcurl的-insecure行为完全匹配。 - 设置
defaultAuthority:对应grpcurl的-authority参数,Istio网关依赖该头信息进行请求路由。 - 注入自定义请求头:通过
CallCredentials添加seldon和namespace头,这是Seldon网关识别目标模型的必要参数。
内容的提问来源于stack exchange,提问作者Sheena
相关产品推荐
相关产品推荐

