我正在尝试使用密钥库文件向安全的REST Web服务发送JSON请求,而我正在使用Jersey API。以下是我的代码片段
SslConfigurator sslConfigurator = SslConfigurator.newInstance().trustStoreFile("C:\\Users\\******\\test.keystore").trustStorePassword("password");
SSLContext sslContext = sslConfigurator.createSSLContext();
Client client = ClientBuilder.newBuilder().sslContext(sslContext).build();
WebTarget target = client.target("https://hostname:portnumber").path("resourse/methodname/v1");
Form form = new Form();
form.param("key1", "value1");
form.param("key2", "value2");
Response response = target.request(MediaType.APPLICATION_JSON_TYPE).post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
System.out.println(response);
但是我在最后一行上得到以下异常。
Exception in thread "main" javax.ws.rs.ProcessingException: Already connected
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:264)
at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:684)
at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:681)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:681)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:437)
at org.glassfish.jersey.client.JerseyInvocation$Builder.post(JerseyInvocation.java:343)
at TestMain.main(TestMain.java:29)
Caused by: java.lang.IllegalStateException: Already connected
at sun.net.www.protocol.http.HttpURLConnection.setRequestProperty(HttpURLConnection.java:3014)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.setRequestProperty(HttpsURLConnectionImpl.java:316)
at org.glassfish.jersey.client.internal.HttpUrlConnector.setOutboundHeaders(HttpUrlConnector.java:421)
at org.glassfish.jersey.client.internal.HttpUrlConnector.access$100(HttpUrlConnector.java:96)
at org.glassfish.jersey.client.internal.HttpUrlConnector$4.getOutputStream(HttpUrlConnector.java:384)
at org.glassfish.jersey.message.internal.CommittingOutputStream.commitStream(CommittingOutputStream.java:200)
at org.glassfish.jersey.message.internal.CommittingOutputStream.commitStream(CommittingOutputStream.java:194)
at org.glassfish.jersey.message.internal.CommittingOutputStream.commit(CommittingOutputStream.java:262)
at org.glassfish.jersey.message.internal.OutboundMessageContext.commitStream(OutboundMessageContext.java:816)
at org.glassfish.jersey.client.ClientRequest.writeEntity(ClientRequest.java:545)
at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:388)
at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:285)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:255)
... 10 more
答案 0 :(得分:3)
实际上,球衣中的错误是异常中的错误消息基本上是错误的。请参阅SSLHandshakeException masked by useless IllegalStateException: Already connected
基本上,这意味着服务器和客户端之间的SSL握手存在问题。
异常的原因之一与此有关:Jersey API Doc - 5.9. Securing a Client
... ClientBuilder还提供了一种定义自定义HostnameVerifier实现的方法。当默认主机URL验证失败时,将调用HostnameVerifier实现。
重要
HostnameVerifier的行为取决于http客户端 实现。 HttpUrlConnector和ApacheConnector正常工作, 这意味着在URL验证失败后 调用HostnameVerifier并通过它来实现 使用HostnameVerifier的自定义实现重新验证URL 继续进行手工处理。 JettyConnector和GrizzlyConnector 仅提供主机URL验证并抛出CertificateException 没有任何可能使用自定义HostnameVerifier。而且,在 JettyConnector的情况有一个属性 JettyClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION禁用 握手中的整个主机URL验证机制。
如果您正在使用Grizzly,则无法将其关闭,但有一种解决方法。要设置一个自定义的HostnameVerifier,验证()始终在客户端配置中返回true:
Client c = ClientBuilder.newBuilder().sslContext(sslContext).hostnameVerifier(new HostnameVerifier(){
@Override
public boolean verify(String paramString, SSLSession paramSSLSession) {
return true;
}
}).build();