java - Can I call an xml-rpc service with gRPC and basic auth?
问题描述
I have the requirement to do a Java call to a xml-rpc service provided by an external editor.
It's an old protocol, but since it's external I don't have a choice over it.
I have the url, a login and a password for authentication.
I have a working prototype, using java 11 and the library apache xml-rpc.
Here is my working code :
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setBasicUserName("some-usr");
config.setBasicPassword("some-pwd");
config.setServerURL(URL url = new URL("https://my-editor/my-service/rpc/"));
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
Map<String, Object> requestMap = ...;
Map<String, Object> responseMap = (Map<String, Object>) client.execute("my-rpc-method", new Object[]{requestMap});
Note that I don't have the port.
This works with java.util.Map as input/output, and I use jackson to convert plain model objects to/from Map.
This is all well and good, however I have two main gripes with apache xml-rpc :
- It's not maintained anymore - latest version is more than 10 years old
- It doesn't have logging capability for the requests and responses exchanged (except by hacking it)
So I searched for alternatives implementations, and am actually looking at gRPC. I have to define some king of contract definition file (.protobuff) which I use for client code generation; no problem with that.
However I can't make the call work for two reasons :
- I'm not sure of the url syntax to use, so I can't even reach the server
- I'm not sure how to do the auth part - I think I have to extend the CallCredentials class, but because of first reason I don't even reach the overriden method
Here is my first attempt (mots of the classes are generated by some .protobuff facilities) :
public class MyCred extends CallCredentials {
@Override
public void applyRequestMetadata(RequestInfo requestInfo, Executor appExecutor, MetadataApplier applier) {
System.out.println("should see this");
}
@Override
public void thisUsesUnstableApi() {}
}
ManagedChannelBuilder<?> forTarget = ManagedChannelBuilder.forAddress("https://my-editor/my-service/rpc/", 443);
MyServiceBlockingStub blockingStub = MyServiceGrpc
.newBlockingStub(forTarget.build())
.withCallCredentials(new MyCred());
MyRpcRequest request = MyRpcRequest.newBuilder()
.setFirstname("dummy-firstname")
.setLastname("dummy-lastname").build();
MyRpcResponse response = blockingStub.myRpcMethod(request);
It requires a port, and since I don't know what it is, I tried what seems to be the default one (but that may be wrong).
This gives me the following error on the ChannelBuilder initialization :
java.lang.IllegalArgumentException: Invalid host or port: https://my-editor/my-service/rpc/ 443
at io.grpc.internal.GrpcUtil.authorityFromHostAndPort(GrpcUtil.java:520)
at io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.forAddress(NettyChannelBuilder.java:135)
at io.grpc.netty.shaded.io.grpc.netty.NettyChannelProvider.builderForAddress(NettyChannelProvider.java:38)
at io.grpc.netty.shaded.io.grpc.netty.NettyChannelProvider.builderForAddress(NettyChannelProvider.java:24)
at io.grpc.ManagedChannelBuilder.forAddress(ManagedChannelBuilder.java:39)
...
Caused by: java.net.URISyntaxException: Expected closing bracket for IPv6 address at index 9: //[https://my-editor/my-service/rpc/]:443
at java.base/java.net.URI$Parser.fail(URI.java:2915)
at java.base/java.net.URI$Parser.failExpecting(URI.java:2921)
at java.base/java.net.URI$Parser.parseServer(URI.java:3294)
at java.base/java.net.URI$Parser.parseAuthority(URI.java:3218)
at java.base/java.net.URI$Parser.parseHierarchical(URI.java:3160)
at java.base/java.net.URI$Parser.parse(URI.java:3127)
at java.base/java.net.URI.<init>(URI.java:685)
at io.grpc.internal.GrpcUtil.authorityFromHostAndPort(GrpcUtil.java:518)
I tried replacing the first line with :
ManagedChannelBuilder<?> forTarget = ManagedChannelBuilder.forTarget("https://my-editor/my-service/rpc/");
I also get an error, on building the Channel :
java.lang.IllegalArgumentException: cannot find a NameResolver for https://my-editor/my-service/rpc/
at io.grpc.internal.ManagedChannelImpl.getNameResolver(ManagedChannelImpl.java:763)
at io.grpc.internal.ManagedChannelImpl.getNameResolver(ManagedChannelImpl.java:772)
at io.grpc.internal.ManagedChannelImpl.<init>(ManagedChannelImpl.java:652)
at io.grpc.internal.ManagedChannelImplBuilder.build(ManagedChannelImplBuilder.java:615)
at io.grpc.internal.AbstractManagedChannelImplBuilder.build(AbstractManagedChannelImplBuilder.java:261)
What am I doing wrong? Is it even possible to migrate my old code to gRPC ?
I found two more recent librairies and made them work, but they have similar flaws :
- Seems not maintained
- Not much (if any) request/response logging
These are :
As a final note, I'm also interested in any code example using alternative libraries, providing they are maintained and have decent logging.
Maybe CXF or Jakarte EE ? I had a look but the APIs are quite confusing; and seem to require a wsdl (which would mean SOAP only).
Or maybe some facilities in Spring (my app will be Spring-based) ?
Any thoughts ?
解决方案
推荐阅读
- java - Nutch - 解析自定义 HTML 元素
- excel - 如何通过 Excel/Access vba 检查物理内存 (RAM) DDR 类型?
- javascript - javascript对象中平面数组的函数式编程方法
- django - 将警报消息(数据)从一个登录用户会话发送到另一个
- knockout.js - 如何在 Dukescript 中定义可写的计算 observables?
- android - Volley 发送数据时改变的数据类型
- excel - 如何删除熊猫中的字符串
- android - 为什么我没有从 FusedLocationProviderClient 的 requestLocationUpdates 方法获得足够的位置
- swift - 如何在 Swift 4 中隐藏默认的 GSMapView InfoWindowOfMarker UIView 框架?
- haskell - 使用 2 个选项生成自定义数据类型的选择