我用 Java 创建了一个 Web 服务客户端,它使用 JAXB 和客户端代理成功调用了一个 Web 服务,并使用 MTOM 发送二进制数据。
该服务现在需要 SSL。在更新我的客户端代码以提供 SSL 连接后,我可以成功进行不需要二进制附件的调用,但需要二进制附件的调用会挂起。永远不会收到来自服务的响应。最终我的客户超时了。
我怎样才能让它工作?使用 SSL 时是否需要做一些特别的事情来启用 MTOM?我已经搜索了这个站点和网络,没有看到其他关于此的报告。
我从在服务器端观看网络数据包的人那里得到了一些信息。我解释一下,因为我不完全理解:他说 TLS 已启动并传输数据,但随后它再次进入 TLS 加密握手并停止。他想知道是否为 MTOM 生成了一个单独的 TLS 会话,而我的应用程序认为已经建立了一个 TLS 会话,并且没有像应有的那样进行证书的初始交换。我不知道如何检查它,因为它都在低级库代码中,而且我没有它的源代码。
我对 Web 服务和 SSL 非常非常陌生。
创建 Web 服务的代码如下:
private MyService getService() throws Exception {
SSLHelper.initializeConduitForSSL(new File("d:/keystore.jks"), "jks", "changeit");
final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(MyService.class);
factory.setAddress("https://" + endPoint); // endpoint not shown in this code
service = (MyService)factory.create();
final Client client = ClientProxy.getClient(service);
final HTTPConduit http = (HTTPConduit)client.getConduit();
http.setTlsClientParameters(SSLHelper.getTlsParams());
final Map<String, Object> ctxt = ((BindingProvider)publishingService).getRequestContext();
// Enable HTTP chunking mode, otherwise HttpURLConnection buffers
ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
return service;
}
为了发出请求,我在返回的服务对象上调用方法。
SSLHelper 是我自己处理证书设置的类。我相信那部分不是问题,所以我不会在此处包含该设置代码。(因为我可以使用相同的 SSL 配置发出其他请求,所以我假设这不是问题。)
对于 MTOM 调用,该方法接受一个参数,该参数是一个请求类的实例,该类具有如下指定的字段(带有适当的 setter):
@XmlElement(required = true)
@XmlMimeType("application/octet-stream")
private DataHandler dataHandler;
要初始化此类,我执行以下操作:
File file = new File("c:\\somefile.jpg"); //
final DataSource dataSource = new FileDataSource(file);
request.setDataHandler(new DataHandler(dataSource));
DataHandler 和 FileDataSource 在 javax.activation 包中。
最后一件事。服务的所有者能够使用 MTOM 成功调用此请求,但他们正在使用以下内容来启用 SSL:
System.setProperty("javax.net.ssl.keyStore", keyStorePath);
System.setProperty("javax.net.ssl.keyStoreType", "jks");
System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword);
我不能这样做,因为在同一个 JVM 中,我们使用多个密钥存储来连接不同的 Web 服务。