在日常开发中,我们访问的链接接口一般都是http,但是现在为了数据在传输过程中的安全,很多网站或者接口都升级为https,那么我们以前的接口如何在改动不大的情况下也能够支持呢?本篇主要讲解JAVA如何在https下应用访问接口,代码1
package com.https.test.url;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Map;
public class test {
public static void main(String[] args) {
try {
System.out.println(post("http://www.baidu.com",null));
//报错测试
//System.out.println(post("https://api.ssllabs.com",null));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String post(String path,Map<String, String> parameters) throws IOException{
String resStr = "";
URL url = new URL(path);
if (parameters != null) {
url = new URL(url.toString() + buildGetParameterString(parameters));
}
InputStream inputStream = url.openStream();
int nextByteOfData = 0;
StringBuffer apiResponseBuffer = new StringBuffer();
while ((nextByteOfData = inputStream.read()) != -1) {
apiResponseBuffer.append((char) nextByteOfData);
}
resStr = apiResponseBuffer.toString();
return resStr;
}
private static String buildGetParameterString(Map<String, String> parameters)
{
String getParameterString = "";
for(Map.Entry<String, String> param : parameters.entrySet())
{
if(param.getValue() == null)
{
continue;
}
getParameterString += (getParameterString.length() < 1) ? ("?") : ("&");
getParameterString += param.getKey() + "=" + param.getValue();
}
return (getParameterString);
}
}
代码1中,访问http是没有任何问题的,但是在访问https的时候,出现报错情况,如下图
这是缺少安全证书时出现的异常,解决方案有两种,一种是把你需要访问的地址网站的证书导入到系统中,第二种实现X509TrustManager管理器,然后把管理器初始化到sslContext对象中。关于第一种导入到系统就不说了,也可以参考
写的还是比较详细的,基本也差不多。
接下来我们来看一下第二种方式。代码如下
实现X509TrustManager管理器
package com.itrus.test.cn.dynamicsCert;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
/**
*
* @author hukai
*实现不需要加载证书,访问https网站或者接口
*
*
*/
public class MyX509TrustManager implements X509TrustManager {
/*
* The default X509TrustManager returned by SunX509. We'll delegate
* decisions to it, and fall back to the logic in this class if the
* default X509TrustManager doesn't trust it.
*/
/*
* Delegate to the default trust manager.
*/
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
/*
* Delegate to the default trust manager.
*/
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
/*
* Merely pass this through.
*/
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
下面是如何使用,在代码1中进行改造
package com.https.test.url;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Map;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
public class test2 {
public static void main(String[] args) {
try {
try {
System.out.println(post("https://www.baidu.com",null));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
System.out.println(post("https://api.ssllabs.com",null));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String post(String path,Map<String, String> parameters) throws IOException, NoSuchAlgorithmException, GeneralSecurityException{
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(path);
HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
httpsConn.setSSLSocketFactory(ssf);
httpsConn.setDoInput(true);// 打开输入流,以便从服务器获取数据
httpsConn.setDoOutput(true);// 打开输出流,以便向服务器提交数据
if (parameters != null) {
url = new URL(url.toString() + buildGetParameterString(parameters));
}
BufferedReader in = new BufferedReader(new InputStreamReader(
httpsConn.getInputStream()));
String line;
StringBuffer rt = new StringBuffer();
while ((line = in.readLine()) != null) {
rt.append(line);
}
return rt.toString();
}
private static String buildGetParameterString(Map<String, String> parameters)
{
String getParameterString = "";
for(Map.Entry<String, String> param : parameters.entrySet())
{
if(param.getValue() == null)
{
continue;
}
getParameterString += (getParameterString.length() < 1) ? ("?") : ("&");
getParameterString += param.getKey() + "=" + param.getValue();
}
return (getParameterString);
}
}
两种方式都各有优缺点,第一种加载证书的方式优点是直接可以不用修改代码,但是过程繁琐,而且证书是存在有效期的,再签发的话,也是算另外一张证书了,以前的证书就不能在用了,需要重新制作证书,把原来过期的证书替换掉。
第二种方式好处在与不用关心证书过期的问题,因为不验证ssl的证书,但是在安全性方面可能存在隐患。