我正在尝试从我的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();
}
*/
}
答案 0 :(得分:1)
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()
)。