自定义 GRPC 客户端存根 - 流未启动



我正在尝试从我的Android应用程序访问带有TLS的自定义GRPC服务器(Anki Vector机器人(。

我的 Android Studio 项目中有原型文件,所有必需的依赖项都可用。Proto文件生成java类,在我的活动中,我使用OkHttpChannelBuilder构建了一个通道。然后我创建一个客户端存根(尝试使用异步和阻塞存根(

之后,我创建一个请求消息并将其与存根一起发送。

代码编译良好,应用程序在我的手机上运行。但是,当发送请求时,我收到一条错误消息,指出流未启动。

在我能找到的所有示例中,我没有看到任何启动流的方法。

阻止流启动的问题可能是什么?

我收到的错误消息:

2019-02-10 01:08:59.303 14691-30895/com.test.anki.grpc D/vectorCTRL: Failed... : 
    java.lang.IllegalStateException: Not started
        at com.google.common.base.Preconditions.checkState(Preconditions.java:510)
        at io.grpc.internal.ClientCallImpl.request(ClientCallImpl.java:367)
        at io.grpc.PartialForwardingClientCall.request(PartialForwardingClientCall.java:34)
        at io.grpc.ForwardingClientCall.request(ForwardingClientCall.java:22)
        at io.grpc.ForwardingClientCall$SimpleForwardingClientCall.request(ForwardingClientCall.java:44)
        at io.grpc.PartialForwardingClientCall.request(PartialForwardingClientCall.java:34)
        at io.grpc.ForwardingClientCall.request(ForwardingClientCall.java:22)
        at io.grpc.ForwardingClientCall$SimpleForwardingClientCall.request(ForwardingClientCall.java:44)
        at io.grpc.PartialForwardingClientCall.request(PartialForwardingClientCall.java:34)
        at io.grpc.ForwardingClientCall.request(ForwardingClientCall.java:22)
        at io.grpc.stub.ClientCalls.startCall(ClientCalls.java:314)
        at io.grpc.stub.ClientCalls.asyncUnaryRequestCall(ClientCalls.java:280)
        at io.grpc.stub.ClientCalls.futureUnaryCall(ClientCalls.java:189)
        at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:127)
        at Anki.Vector.external_interface.ExternalInterfaceGrpc$ExternalInterfaceBlockingStub.sayText(ExternalInterfaceGrpc.java:3554)
        at com.test.anki.grpc.MainActivity.testapi(MainActivity.java:1106)
        at com.test.anki.grpc.MainActivity$GrpcTask.doInBackground(MainActivity.java:1003)
        at com.test.anki.grpc.MainActivity$GrpcTask.doInBackground(MainActivity.java:996)
        at android.os.AsyncTask$2.call(AsyncTask.java:333)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)

我的代码是:

       ClientInterceptor clientInterceptor = new ClientInterceptor() {
            @Override
            public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> methodDescriptor, CallOptions callOptions, Channel channel) {
                // Might need to try to inject the token using that?
                return new ClientInterceptors.CheckedForwardingClientCall<ReqT, RespT>(channel.newCall(methodDescriptor, callOptions)) {
                    @Override
                    protected void checkedStart(Listener listener, Metadata metadata) throws Exception {
                        Metadata.Key<String> key = Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);
                        metadata.put(key, token);
                    }
                };
            }
        };
        SSLContext sslContext=null ;
        try {
            sslContext  = SSLContext.getInstance("TLS");
            sslContext .init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
            SSLContext.setDefault(sslContext );
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (KeyManagementException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        OkHttpClient okHttpClient = new OkHttpClient();
        okHttpClient.setSslSocketFactory(sslSocketFactory);
        okHttpClient.setHostnameVerifier(new HostnameVerifier() {
            @Override public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
        Channel channel=null;
        try {
            //ManagedChannel channel = OkHttpChannelBuilder.forAddress(ipaddr, Integer.valueOf(port))
                    channel = OkHttpChannelBuilder.forAddress(ipaddr, Integer.valueOf(port))
                    //.overrideAuthority("Vector")
                    .sslSocketFactory(sslSocketFactory)
                    .intercept(clientInterceptor)
                    .build();
            //ExternalInterfaceGrpc.ExternalInterfaceStub externalInterfaceStub = ExternalInterfaceGrpc.newStub(channel);
            ExternalInterfaceGrpc.ExternalInterfaceBlockingStub externalInterfaceBlockingStub = ExternalInterfaceGrpc.newBlockingStub(channel);
            Messages.SayTextRequest sayTextRequest = Messages.SayTextRequest
                    .newBuilder()
                    .setText("Yolo")
                    .build();
            Messages.SayTextResponse res = externalInterfaceBlockingStub.sayText(sayTextRequest);
            Log.d(TAG, res.getStatus().toString());
} catch (Exception e) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            pw.flush();
            Log.d(TAG,String.format("Failed... : %n%s", sw));
        } finally {
            Log.d(TAG,"finally");
            /*
            try {
                 if(channel!=null) {((ManagedChannel) channel).shutdown().awaitTermination(1, TimeUnit.SECONDS);}
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            */
        }

ClientCall需要调用start()。 如果使用存根,则不需要调用start(),因为存根本身会调用start()。但是拦截器暴露在start().

问题出在您的clientInterceptor

protected void checkedStart(Listener listener, Metadata metadata) throws Exception {
    Metadata.Key<String> key = Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);
    metadata.put(key, token);
    // FIXME: Missing call to delegate().start(listener, metadata);
}

名为start()的存根最终调用了拦截器的checkedStart(),但随后拦截器没有在真正的ClientCall上调用start。

请注意,您不需要使用 CheckedForwardingClientCall,因为您的checkedStart()不会引发任何异常。 ForwardingClientCall是更常用的类。(覆盖start()而不是checkedStart()(。

最新更新