最近在調用一些https的接口,然後採用的認證方式是用戶名+密碼。
這個時候調用接口則會提示httpclient未認證的錯誤,導致接口無法調用:
HttpClient javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated。
出現此問題主要是在請求過程中證書的問題,程序使用的客戶端並未安裝服務器要求的證書,所以會產生此問題。
下面是我找到的解決方法。
方法一: httpClient jar包版本爲4.1.x
public static HttpClient getHttpClient(HttpClient base) {
try {
SSLContext ctx = SSLContext.getInstance("SSL");
X509TrustManager tm = new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager mgr = base.getConnectionManager();
SchemeRegistry registry = mgr.getSchemeRegistry();
registry.register(new Scheme("https", 443, ssf));
return new DefaultHttpClient(mgr, base.getParams());
} catch (Exception e) {
logger.warn("{}", e);
return null;
}
}
調用的方法如下:
HttpClient httpClient = ToolUtil.getHttpClient(new DefaultHttpClient());
此時問題已經完美解決了。
然而在之後的使用過程中,我發現4.1版本的httpClient jar包裏面沒有httpPatch,但最新的4.5版本是有的。於是果斷用最新的4.5.3版本的httpClient包。
用了這個jar包之後滿屏幕的刪除線,很多代碼都被@Deprecated註解掉了。改!
解決HttpClient javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated這個問題的代碼當然也是要隨着一起改的了,於是乎我找到了方法二。
方法二: httpClient jar包爲4.5.x版本。
public static CloseableHttpClient getHttpClient() {
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}}, new SecureRandom());
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().setSSLSocketFactory(socketFactory).build();
return closeableHttpClient;
} catch (Exception e) {
logger.warn("create closeable http client failed!");
return HttpClientBuilder.create().build();
}
}
調用示例:
httpClient = ToolUtil.getHttpClient();
在這個裏面我遇到的最大問題是SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER 竟然也被@Deprecated註釋了。然後終於找到了一個替代方案:用NoopHostnameVerifier.INSTANCE替換之。這個是在http://stackoverflow.com/questions/23201648/httpclient-4-3-x-fixing-deprecated-code-to-use-current-httpclient-implementatio 最下面一個答案中找到的。
最後附上完整的java代碼,主要是給出import頭文件。
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ToolUtil {
private static final Logger logger = LoggerFactory.getLogger(ToolUtil.class);
public static HttpClient getHttpClient(HttpClient base) {
try {
SSLContext ctx = SSLContext.getInstance("SSL");
X509TrustManager tm = new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager mgr = base.getConnectionManager();
SchemeRegistry registry = mgr.getSchemeRegistry();
registry.register(new Scheme("https", 443, ssf));
return new DefaultHttpClient(mgr, base.getParams());
} catch (Exception e) {
logger.warn("{}", e);
return null;
}
}
public static CloseableHttpClient getHttpClient() {
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}}, new SecureRandom());
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().setSSLSocketFactory(socketFactory).build();
return closeableHttpClient;
} catch (Exception e) {
logger.warn("create closeable http client failed!");
return HttpClientBuilder.create().build();
}
}
}
本文參考: