java调用HTTPS

 这两天在做与渠道联调的回调,其中回调渠道的时候使用的是https。

简单的测试代码如下;

 

public static void simpleTest(String httpsURL) throws Exception {
	URL myurl = new URL(httpsURL);
	HttpsURLConnection con = (HttpsURLConnection) myurl.openConnection();
	InputStream ins = con.getInputStream();
	InputStreamReader isr = new InputStreamReader(ins);
	BufferedReader in = new BufferedReader(isr);
	String inputLine;
	while ((inputLine = in.readLine()) != null) {
		System.out.println(inputLine);
	}
	in.close();
}

 

但是,如果为自签发的SSL证书(未提供证书发行链而不被信任)的请求地址,上面的代码就不起作用了。

错误为:

 Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target。

 

经过查找资料,现有两种解决方案:

1)为自身系统增加证书

 

2)绕过证书验证

 

先来说第一种方案:

1)用IE打开访问的https网址,点击地址栏后面的小锁头(或证书错误标识),查看证书。在弹出的证书信息框中选择第二个页签“详细信息”。点击复制到文件,选择Base64编码的X.509证书导出即可。

2)把证书从其它文件导入到TrustStore文件中。

keytool -import -file D:/test1.cer -keystore D:/crt_test1

执行命令后要求输入密码,记住输入的密码。

 

3)编写如下代码:

 

public static void certTest1()throws Exception{
		String httpsURL = "https://xxx.xxx.cn/";
		String trustStor="D:/crt_test1";
		System.setProperty("javax.net.ssl.trustStore", trustStor);
		URL myurl = new URL(httpsURL);
		HttpsURLConnection con = (HttpsURLConnection) myurl.openConnection();
		con.setHostnameVerifier(hv);
		InputStream ins = con.getInputStream();
		InputStreamReader isr = new InputStreamReader(ins);
		BufferedReader in = new BufferedReader(isr);
		String inputLine=null;
		while ((inputLine = in.readLine()) != null) {
			System.out.println(inputLine);
		}
		in.close();
}
private static HostnameVerifier hv = new HostnameVerifier() {
		public boolean verify(String urlHostName, SSLSession session) {
			return urlHostName.equals(session.getPeerHost());
		}
};

 可是如果出现两个https地址并且证书不同的话,上面的代码就没有办法处理了。有人可能说用System.setProperty重新设置一下trustStore,很抱歉,我试了好几次,没有成功。如果他人有成功的请给出代码,谢谢。

 

为了处理两个证书的情况,我又查了下资料,整理一下,使用TrustManager来处理(此时会用到证书的密码)。

代码如下:

public static void certTest2(String certDir, String passwd, String urlStr)
		throws Exception {
	SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
	TrustManager[] tms = getTms(certDir, passwd);
	sslContext.init(null, tms, new java.security.SecureRandom());
	SSLSocketFactory ssf = sslContext.getSocketFactory();

	URL url = new URL(urlStr);
	HttpsURLConnection.setDefaultHostnameVerifier(hv);
	HttpsURLConnection conn = ((HttpsURLConnection) url.openConnection());
	conn.setSSLSocketFactory(ssf);

	InputStreamReader im = new InputStreamReader(conn.getInputStream(),
			"GBK");
	BufferedReader reader = new BufferedReader(im);
	StringBuffer sb = new StringBuffer();
	String line = null;
	while ((line = reader.readLine()) != null) {
		sb.append(line + "\r\n");
	}
	System.out.println(sb);
}

public static TrustManager[] getTms(String dir, String keyPassword)
		throws Exception {
	String talg = TrustManagerFactory.getDefaultAlgorithm();
	TrustManagerFactory tmFact = TrustManagerFactory.getInstance(talg);
	FileInputStream tfis = new FileInputStream(dir);
	KeyStore ts = KeyStore.getInstance("jks");
	ts.load(tfis, keyPassword.toCharArray());
	tfis.close();
	tmFact.init(ts);
	return tmFact.getTrustManagers();
}
private static HostnameVerifier hv = new HostnameVerifier() {
	public boolean verify(String urlHostName, SSLSession session) {
		return urlHostName.equals(session.getPeerHost());
	}
};

 再说第二种方案:

不多说,直接上代码

public static void withoutCertTest(String urlStr) throws Exception {
	SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
	TrustManager[] tms = { ignoreCertificationTrustManger };
	sslContext.init(null, tms, new java.security.SecureRandom());
	SSLSocketFactory ssf = sslContext.getSocketFactory();

	URL url = new URL(urlStr);
	HttpsURLConnection.setDefaultHostnameVerifier(hv);
	HttpsURLConnection conn = ((HttpsURLConnection) url.openConnection());
	conn.setSSLSocketFactory(ssf);

	InputStreamReader im = new InputStreamReader(conn.getInputStream(),
			"GBK");
	BufferedReader reader = new BufferedReader(im);
	StringBuffer sb = new StringBuffer();
	String line = null;
	while ((line = reader.readLine()) != null) {
		sb.append(line + "\r\n");
	}
	System.out.println(sb);
}

private static TrustManager ignoreCertificationTrustManger = new X509TrustManager() {

	private X509Certificate[] certificates;

	@Override
	public void checkClientTrusted(X509Certificate certificates[],
			String authType) throws CertificateException {
		if (this.certificates == null) {
			this.certificates = certificates;
		}
	}

	@Override
	public void checkServerTrusted(X509Certificate[] ax509certificate,
			String s) throws CertificateException {
		if (this.certificates == null) {
			this.certificates = ax509certificate;
		}
	}

	@Override
	public X509Certificate[] getAcceptedIssuers() {
		return null;
	}
};

 参考网址:

http://guoguanfei.blog.163.com/blog/static/555830372009217115420766/

http://blog.csdn.net/c_4818/article/details/7825388

http://www.wenhq.com/article/view_711.html

 ===========================================================

以上测试以后,与渠道调用的时候并没有成功,于是使用apache提供的HttpClients,问题解决。

代码如下:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;

/**
 * HttpClientUtils, 使用 HttpClient 4.x<br>
 * 
 */
public class HttpClientUtils {

	private static HttpClient client = null;
	static {
		PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
		cm.setMaxTotal(128);
		cm.setDefaultMaxPerRoute(128);
		client = HttpClients.custom().setConnectionManager(cm).build();
	}

	/**
	 * 发送一个 Post 请求, 使用指定的字符集编码.
	 * 
	 * @param url
	 * @param body
	 *            RequestBody
	 * @param mimeType
	 *            例如 application/xml
	 * @param charset
	 *            编码
	 * @param connTimeout
	 *            建立链接超时时间,毫秒.
	 * @param readTimeout
	 *            响应超时时间,毫秒.
	 * @return ResponseBody, 使用指定的字符集编码.
	 * 
	 * @throws ConnectTimeoutException
	 *             建立链接超时异常
	 * @throws SocketTimeoutException
	 *             响应超时
	 * @throws Exception
	 */
	public static String post(String url, String body, String mimeType,
			String charset, Integer connTimeout, Integer readTimeout)
			throws ConnectTimeoutException, SocketTimeoutException, Exception {
		HttpClient client = null;
		HttpPost post = new HttpPost(url);
		String result = "";
		try {
			if (StringUtils.isNotBlank(body)) {
				HttpEntity entity = new StringEntity(body, ContentType.create(
						mimeType, charset));
				post.setEntity(entity);
			}
			// 设置参数
			Builder customReqConf = RequestConfig.custom();
			if (connTimeout != null) {
				customReqConf.setConnectTimeout(connTimeout);
			}
			if (readTimeout != null) {
				customReqConf.setSocketTimeout(readTimeout);
			}
			post.setConfig(customReqConf.build());

			HttpResponse res;
			if (url.startsWith("https")) {
				// 执行 Https 请求.
				client = createSSLInsecureClient();
				res = client.execute(post);
			} else {
				// 执行 Http 请求.
				client = HttpClientUtils.client;
				res = client.execute(post);
			}
			result = IOUtils.toString(res.getEntity().getContent(), charset);
		} finally {
			post.releaseConnection();
			if (url.startsWith("https") && client != null
					&& client instanceof CloseableHttpClient) {
				((CloseableHttpClient) client).close();
			}
		}
		return result;
	}

	/**
	 * 提交form表单
	 * 
	 * @param url
	 * @param params
	 * @param connTimeout
	 * @param readTimeout
	 * @return
	 * @throws ConnectTimeoutException
	 * @throws SocketTimeoutException
	 * @throws Exception
	 */
	public static String postForm(String url, Map<String, String> params,
			Map<String, String> headers, Integer connTimeout,
			Integer readTimeout) throws ConnectTimeoutException,
			SocketTimeoutException, Exception {

		HttpClient client = null;

		HttpPost post = new HttpPost(url);
		try {
			if (params != null && !params.isEmpty()) {
				List<NameValuePair> formParams = new ArrayList<org.apache.http.NameValuePair>();
				Set<Entry<String, String>> entrySet = params.entrySet();
				for (Entry<String, String> entry : entrySet) {
					formParams.add(new BasicNameValuePair(entry.getKey(), entry
							.getValue()));
				}
				UrlEncodedFormEntity entity = new UrlEncodedFormEntity(
						formParams, Consts.UTF_8);
				post.setEntity(entity);
			}
			if (headers != null && !headers.isEmpty()) {
				for (Entry<String, String> entry : headers.entrySet()) {
					post.addHeader(entry.getKey(), entry.getValue());
				}
			}
			// 设置参数
			Builder customReqConf = RequestConfig.custom();
			if (connTimeout != null) {
				customReqConf.setConnectTimeout(connTimeout);
			}
			if (readTimeout != null) {
				customReqConf.setSocketTimeout(readTimeout);
			}
			post.setConfig(customReqConf.build());
			HttpResponse res = null;
			if (url.startsWith("https")) {
				// 执行 Https 请求.
				client = createSSLInsecureClient();
				res = client.execute(post);
			} else {
				// 执行 Http 请求.
				client = HttpClientUtils.client;
				res = client.execute(post);
			}
			return IOUtils.toString(res.getEntity().getContent(), "UTF-8");
		} finally {
			post.releaseConnection();
			if (url.startsWith("https") && client != null
					&& client instanceof CloseableHttpClient) {
				((CloseableHttpClient) client).close();
			}
		}
	}

	/**
	 * 发送一个 GET 请求
	 * 
	 * @param url
	 * @param charset
	 * @return
	 * @throws Exception
	 */
	public static String get(String url, String charset) throws Exception {
		return get(url, charset, null, null);
	}

	/**
	 * 发送一个 GET 请求
	 * 
	 * @param url
	 * @param charset
	 * @param connTimeout
	 *            建立链接超时时间,毫秒.
	 * @param readTimeout
	 *            响应超时时间,毫秒.
	 * @return
	 * @throws ConnectTimeoutException
	 *             建立链接超时
	 * @throws SocketTimeoutException
	 *             响应超时
	 * @throws Exception
	 */
	public static String get(String url, String charset, Integer connTimeout,
			Integer readTimeout) throws ConnectTimeoutException,
			SocketTimeoutException, Exception {
		HttpClient client = null;

		HttpGet get = new HttpGet(url);
		String result = "";
		try {
			// 设置参数
			Builder customReqConf = RequestConfig.custom();
			if (connTimeout != null) {
				customReqConf.setConnectTimeout(connTimeout);
			}
			if (readTimeout != null) {
				customReqConf.setSocketTimeout(readTimeout);
			}
			get.setConfig(customReqConf.build());

			HttpResponse res = null;

			if (url.startsWith("https")) {
				// 执行 Https 请求.
				client = createSSLInsecureClient();
				res = client.execute(get);
			} else {
				// 执行 Http 请求.
				client = HttpClientUtils.client;
				res = client.execute(get);
			}

			result = IOUtils.toString(res.getEntity().getContent(), charset);
		} finally {
			get.releaseConnection();
			if (url.startsWith("https") && client != null
					&& client instanceof CloseableHttpClient) {
				((CloseableHttpClient) client).close();
			}
		}
		return result;
	}

	/**
	 * 从 response 里获取 charset
	 * 
	 * @param ressponse
	 * @return
	 */
	@SuppressWarnings("unused")
	private static String getCharsetFromResponse(HttpResponse ressponse) {
		// Content-Type:text/html; charset=GBK
		if (ressponse.getEntity() != null
				&& ressponse.getEntity().getContentType() != null
				&& ressponse.getEntity().getContentType().getValue() != null) {
			String contentType = ressponse.getEntity().getContentType()
					.getValue();
			if (contentType.contains("charset=")) {
				return contentType
						.substring(contentType.indexOf("charset=") + 8);
			}
		}
		return null;
	}

	private static CloseableHttpClient createSSLInsecureClient()
			throws GeneralSecurityException {
		try {
			SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(
					null, new TrustStrategy() {
						public boolean isTrusted(X509Certificate[] chain,
								String authType) throws CertificateException {
							return true;
						}
					}).build();
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
					sslContext, new X509HostnameVerifier() {

						@Override
						public boolean verify(String arg0, SSLSession arg1) {
							return true;
						}

						@Override
						public void verify(String host, SSLSocket ssl)
								throws IOException {
						}

						@Override
						public void verify(String host, X509Certificate cert)
								throws SSLException {
						}

						@Override
						public void verify(String host, String[] cns,
								String[] subjectAlts) throws SSLException {
						}

					});
			return HttpClients.custom().setSSLSocketFactory(sslsf).build();
		} catch (GeneralSecurityException e) {
			throw e;
		}
	}

	public static void main(String[] args) {
		try {
			String xml = IOUtils.toString(new FileInputStream(new File(
					"D:\\hongkangtest.txt")));
			System.out
					.println(post(
							"https://trade.tongbanjie.com/insurance/callback/hk/redeem.htm",
							xml, "html/text", "GBK", 10000, 10000));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 依赖的jar包有:commons-lang-2.6.jar、httpclient-4.3.2.jar、httpcore-4.3.1.jar、commons-io-2.4.jar

 

 

 

你可能感兴趣的:(https)