这是本人开通账号后的第一篇文章,平时上班比较忙没有多余的时间来写博客,今天难得闲下来统计下前两天遇到的一个问题以及我的处理方式。
事情发生在2天前,我使用httpclient调用第三方接口时,没有注意第三方接口是https的,众所周知httpClient是不能直接调用https的,直接调用会报SSL证书相关错误,刚开始呢没注意是我的工具类的问题,提示我没有信任该域名的证书,于是我把域名对应的证书下载下来添加到了本地的jre信任中去,解决了这个问题。可以参考以下的链接:
彻底解决unable to find valid certification path to requested target - 进击的Ace - 博客园
现在问题是解决了,接口也调通了,但新的问题又来了,我是要发布在测试环境进行测试的,测试通过后还要部署在正式环境上去,现在这样操作岂不是两边的服务器我都要添加jre信任才行吗?也是直到这个时候我才发现原来是我的工具类是httpClient调用的原因,附上我的工具类~
如下:
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
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.util.EntityUtils;
import java.io.IOException;
public class HttpClientUtil {
public static String doPostJson(String url, String json) {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
HttpPost httpPost = new HttpPost(url);
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return resultString;
}
}
此时就有了好的解决方案,直接换一个工具类就行,但是如果说我非要使用httpClient工具类调用https的第三方接口该怎么处理呢?是否有相关的代码或者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.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class SSLClient extends DefaultHttpClient {
public SSLClient() throws Exception{
super();
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = this.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", 443, ssf));
}
}
按照我和我同事大神钻(hu)研(shuo)得(ba)出(dao),这个工具类可以让我们使用httpClient工具类调用https接口时忽略证书,或者说不去验证证书。于是我修改了下我的httpClient工具类,附图~
代码如下:
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
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.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
public class HttpClientUtil {
public static String doPostJson(String url, String json) {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
HttpPost httpPost = new HttpPost(url);
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return resultString;
}
public static String doPost(String url,String jsonstr){
HttpClient httpClient = null;
HttpPost httpPost = null;
String result = null;
try{
httpClient = new SSLClient();
httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type", "application/json");
if(jsonstr != null){
StringEntity se = new StringEntity(jsonstr);
se.setContentType("text/json");
se.setContentEncoding(new BasicHeader("Content-Type", "application/json"));
httpPost.setEntity(se);
}
HttpResponse response = httpClient.execute(httpPost);
if(response != null){
HttpEntity resEntity = response.getEntity();
if(resEntity != null){
result = EntityUtils.toString(resEntity,"UTF-8");
}
}
}catch(Exception ex){
ex.printStackTrace();
}
return result;
}
}
之前调用的是httpclient.doPostJson方法,修改后直接调用.doPost方法,本地测试和在生产环境都没问题,完美解决~
不知道这种方法会不会存在弊端,欢迎各位前辈在评论区指出错误。
PS:这种方法仅适用于强迫症程序员,正常调用还请另使用RestTemplate相关模板~