java 通过 Jersey 发送请求时出现 javax.ws.rs.ProcessingException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34280861/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 22:40:44  来源:igfitidea点击:

javax.ws.rs.ProcessingException while sending request through Jersey

javaweb-servicesrestjersey

提问by Ram Vibhakar

I am trying to send a JSON request to a secure REST webservice using a keystore file and I am using Jersey API. Below is the snippet of my code

我正在尝试使用密钥库文件将 JSON 请求发送到安全的 REST web 服务,并且我正在使用 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);

But I am getting the following exception on the last but one line.

但是我在最后一行出现以下异常。

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.call(JerseyInvocation.java:684)
at org.glassfish.jersey.client.JerseyInvocation.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.access0(HttpUrlConnector.java:96)
at org.glassfish.jersey.client.internal.HttpUrlConnector.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

回答by Kin Cheung

It is actually a bug in jersey that the error message in the exception is basically wrong. Please see SSLHandshakeException masked by useless IllegalStateException: Already connected

其实是jersey的一个bug,异常中的错误信息基本是错误的。请参阅SSLHandshakeException 被无用的 IllegalStateException 屏蔽:已连接

So basically, it means that there is a problem in SSL handshaking between the server and client.

所以基本上,这意味着服务器和客户端之间的SSL握手存在问题。

One of the causes of the exception is related to this: Jersey API Doc - 5.9. Securing a Client

异常的原因之一与此有关:Jersey API Doc - 5.9。保护客户

... ClientBuilder also offers a method for defining a custom HostnameVerifier implementation. HostnameVerifier implementations are invoked when default host URL verification fails.

Important

A behaviour of HostnameVerifier is dependent on an http client implementation. HttpUrlConnector and ApacheConnector work properly, that means that after the unsuccessful URL verification HostnameVerifier is called and by means of it is possible to revalidate URL using a custom implementation of HostnameVerifier and go on in a handskahe processing. JettyConnector and GrizzlyConnector provide only host URL verification and throw a CertificateException without any possibility to use custom HostnameVerifier. Moreover, in case of JettyConnector there is a property JettyClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION to disable an entire host URL verification mechanism in a handshake.

... ClientBuilder 还提供了一种用于定义自定义 HostnameVerifier 实现的方法。当默认主机 URL 验证失败时,将调用 HostnameVerifier 实现。

重要的

HostnameVerifier 的行为取决于 http 客户端实现。HttpUrlConnector 和 ApacheConnector 工作正常,这意味着在 URL 验证失败后 HostnameVerifier 被调用,并且可以使用 HostnameVerifier 的自定义实现重新验证 URL 并继续进行手动处理。JettyConnector 和 GrizzlyConnector 仅提供主机 URL 验证并抛出 CertificateException,无法使用自定义 HostnameVerifier。此外,在 JettyConnector 的情况下,有一个属性 JettyClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION 可以在握手中禁用整个主机 URL 验证机制。

If you are using Grizzly, you can't turn it off, but there is a workaround. It is to set a customized HostnameVerifier that the verify() always returns true in the client configuration:

如果您使用的是 Grizzly,则无法将其关闭,但有一个解决方法。就是在客户端配置中设置一个自定义的HostnameVerifier,verify()总是返回true:

        Client c = ClientBuilder.newBuilder().sslContext(sslContext).hostnameVerifier(new HostnameVerifier(){
              @Override
              public boolean verify(String paramString, SSLSession paramSSLSession) {
               return true;
             }
        }).build();