Jersey 2 - 带有 .target HTTPS
Posted
技术标签:
【中文标题】Jersey 2 - 带有 .target HTTPS【英文标题】:Jersey 2 - with .target HTTPS 【发布时间】:2018-09-27 23:44:37 【问题描述】:我一直在尝试从 jersey 客户端执行 POST,但继续遇到以下异常:
原因:java.lang.IllegalStateException:已连接 在 sun.net.www.protocol.http.HttpURLConnection.setRequestProperty(HttpURLConnection.java:3071) 在 sun.net.www.protocol.https.HttpsURLConnectionImpl.setRequestProperty(HttpsURLConnectionImpl.java:325) 在 org.glassfish.jersey.client.internal.HttpUrlConnector.setOutboundHeaders(HttpUrlConnector.java:424) 在 org.glassfish.jersey.client.internal.HttpUrlConnector.lambda$_apply$0(HttpUrlConnector.java:381) 在 org.glassfish.jersey.message.internal.CommittingOutputStream.commitStream(CommittingOutputStream.java:195) 在 org.glassfish.jersey.message.internal.CommittingOutputStream.commitStream(CommittingOutputStream.java:189) 在 org.glassfish.jersey.message.internal.CommittingOutputStream.commit(CommittingOutputStream.java:257) 在 org.glassfish.jersey.message.internal.OutboundMessageContext.commitStream(OutboundMessageContext.java:825) 在 org.glassfish.jersey.client.ClientRequest.doWriteEntity(ClientRequest.java:553) 在 org.glassfish.jersey.client.ClientRequest.writeEntity(ClientRequest.java:498) 在 org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:384) 在 org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:282) 在 org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:278) ... 63 更多
我在 SO 中尝试了很多答案和解决方案,但都没有成功。
这里发疯了,请帮忙!
public class JerseyWithSSL
public static javax.ws.rs.client.Client getRESTClient()
try
TrustManager[] trustMgr = new TrustManager[]new X509TrustManager()
public X509Certificate[] getAcceptedIssuers()
return null;
public void checkClientTrusted1(X509Certificate[] certs,
String authType)
public void checkServerTrusted1(X509Certificate[] certs,
String authType)
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException
// TODO Auto-generated method stub
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException
// TODO Auto-generated method stub
;
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, trustMgr, null);
javax.ws.rs.client.Client client = ClientBuilder.newBuilder().sslContext(context)
.hostnameVerifier(new HostnameVerifier()
@Override
public boolean verify(String arg0, SSLSession arg1)
// TODO Auto-generated method stub
return true;
).build();
return client;
catch (NoSuchAlgorithmException | KeyManagementException ex)
Logger.getLogger(JerseyWithSSL.class.getName()).log(Level.SEVERE, null, ex);
return null;
使用上述类的代码(此处抛出异常):
// send notification to all subscriptors for event: attendee.create
if (!subscriptions.isEmpty())
try
Client client = JerseyWithSSL.getRESTClient();
for (Subscription sub : subscriptions)
System.out.println("Subscription: \n" + sub.getEventName() + "\n" + sub.getTargetUrl());
Response resp = client.target(sub.getTargetUrl())
.request(MediaType.APPLICATION_JSON)
.post(Entity.entity(newAttdee, MediaType.APPLICATION_JSON));
System.out.println("Status: " + resp.getStatus());
System.out.println(resp.getEntity().toString());
resp.close();
catch (Exception ex)
Logger.getLogger(AttendeeResource.class.getName()).log(Level.SEVERE, null, ex);
添加 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ON24Hooks</groupId>
<artifactId>ON24_Zapier_Hooks</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>ON24_Zapier_Hooks</name>
<properties>
<endorsed.dir>$project.build.directory/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.connectors</groupId>
<artifactId>jersey-apache-connector</artifactId>
<version>2.16</version>
<type>jar</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilerArguments>
<endorseddirs>$endorsed.dir</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>$endorsed.dir</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-endorsed-api</artifactId>
<version>7.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
【问题讨论】:
第一次调用本身会发生这种情况吗?错误似乎重用客户端对象可能是? 嗨@TarunLalwani,确实客户端在for循环中使用。更新代码... 你能把Client client = JerseyWithSSL.getRESTClient();
移到循环里面看看有没有帮助?
这有什么更新吗?我假设在循环中移动客户端创建应该为您解决问题
你能不能也分享你的pom.xml
我在resp
上没有看到close
方法
【参考方案1】:
IllegalStateException: Already connected
可能掩盖了 SSLHandshakeException
,如问题 #3000 中所述(以前称为 JERSEY-2728)。
根据release notes,它已在 Jersey 2.23 中修复。不过,我会将泽西岛升级到最新版本。
【讨论】:
我添加了 jersey-client:2.27 和 jersey-apache-connector:2.27 --- 最新版本,问题仍然存在。【参考方案2】:我花了一些时间弄清楚它是如何在 Jersey 2.x 中完成的。感谢Jersey Migration Guide 帮助我。 下面是如何在 Jersey 2.x 中为 HTTPS 调用构建客户端的代码 sn-p
public Client getRESTClient()
TrustManager[] trustMgr= new TrustManager[] new X509TrustManager()
public X509Certificate[] getAcceptedIssuers()
return null;
public void checkClientTrusted1(X509Certificate[] certs,
String authType)
public void checkServerTrusted1(X509Certificate[] certs,
String authType)
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException
// TODO Auto-generated method stub
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException
// TODO Auto-generated method stub
;
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, trustMgr, null);
Client client = ClientBuilder.newBuilder().sslContext(context)
.hostnameVerifier(new HostnameVerifier()
@Override
public boolean verify(String arg0, SSLSession arg1)
// TODO Auto-generated method stub
return true;
).build();
return client;
任何时候都可能发生异常,也可能是 SSL 证书验证,也可以是当前套接字层连接来验证 SSLContext。请彻底调试 try catch 块,也使您的 http 请求与其他客户端的执行也一样来自Java Url URLCONNECTION
【讨论】:
【参考方案3】:IllegalStateException: 已连接可能正在掩盖 SSLHandshakeException。验证/调试的方法是使用以下 JVM 标志:
-Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack
这将导致 JVM 打印出一大堆有关 SSL 的调试信息,如果有 SSL 异常,则会显示该异常。
【讨论】:
以上是关于Jersey 2 - 带有 .target HTTPS的主要内容,如果未能解决你的问题,请参考以下文章
带有 Jersey 2.2 和 Jackson 2.1 的自定义 ObjectMapper
带有 Jersey 客户端版本 2.2 的 Restful WebService 调用
JAX-RS(Jersey 2 实现)内容协商,带有 URL 扩展名 .xml 或 .json
RxJava jersey客户端,带有使用WebResourceFactory构建的代理