随着公司业务的不断扩大,我们跟不同系统的交互就与来越多。在此呢先感谢我们公司的框架部门为我们封装了很多很简便的方法。
比如httpclient的方式:httputil.sendpost(url,map);
又比如webservice的方式:WebServiceUtil.getService(class,url).method();
这些方法一般都能满足我们的需求,里面的参数配置等考虑的都很齐全。但是在特殊情况下,可能需要我们去个性化一种调用方式。
周六本平台对接的另一个系统域名突然从http变更为https。以前使用的webservice接口均无法调用。导致系统无法使用,无奈驱车去公司整改。
1. http与https的区别在于https是ssl加密的,访问较为安全。但java中访问需要证书。
2. 通过传统webservice的方式,wsdl2java -encoding utf-8 https://xxxxxxx?wsdl 无法生成代理类(肯定可以解决该问题并通过webservice访问,但本人对webservice不是很熟).
3. 原代码使用的是框架方法,无法定位具体问题(目前没有https调用webservice的方法)。
1. 在互联网上,请求绝大多数是基于http协议的。不管后台是restful形式还是webservice形式,也不管后台是用.net还是java应该都可以通过模拟http请求来实现调用。
或者换句话说,webservice调用本身就是封装好的http请求(只不过多了数据封装和数据解析的步骤)。
2. 自己有http请求跳过证书验证的经验。
1. 先搞清楚接口的格式。我们可以借用soapUI来看看。
分析这个webservice接口我们可以很轻松拿到几个关键行的参数:请求地址,请求主体(body),数据格式(关系到我们构建和解析数据),http请求的几个关键性参数都得到了。
2. 构建请求主体
我们直接将上面的body拼接起来,并传入参数,在这里有个小细节,参数尽量用
data="";包裹起来以表明传输的是文本,不参与格式的解析。
3. 发送http请求
需要注意http请求头的配置博大精深,我这里设置的相对比较简单。
InputStreamReader bis = null;
OutputStreamWriter printWriter = null;
String body = "";
try {
HttpURLConnection httpURLConnection = SSLTrustManager.connect(url+"?wsdl");
httpURLConnection.setRequestMethod("POST");// 提交模式
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
httpURLConnection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
// 获取URLConnection对象对应的输出流
printWriter = new OutputStreamWriter(httpURLConnection.getOutputStream(), "UTF-8");
// 发送请求参数
printWriter.write(xmldate);
// flush输出流的缓冲
printWriter.flush();
// 开始获取数据
bis = new InputStreamReader(httpURLConnection.getInputStream(), "UTF-8");
int len;
char[] arr = new char[1024];
while ((len = bis.read(arr)) != -1) {
body += new String(arr, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (printWriter != null) {
try {
printWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4. 关于跳过https验证
这个跳过验证在SSLTrustManager这个类里,里面可以跳过https验证,也可以通过加载证书的形式。附上这个类的代码。
import java.net.HttpURLConnection;
import java.net.URL;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
public class SSLTrustManager implements javax.net.ssl.TrustManager,
javax.net.ssl.X509TrustManager ,HostnameVerifier{
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(
java.security.cert.X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(
java.security.cert.X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
@Override
public boolean verify(String urlHostName, SSLSession session) { //允许所有主机
return true;
}
public static HttpURLConnection connect(String strUrl) throws Exception {
javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
javax.net.ssl.TrustManager tm = new SSLTrustManager();
trustAllCerts[0] = tm;
javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
.getInstance("SSL");
sc.init(null, trustAllCerts, null);
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc
.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier((HostnameVerifier) tm);
URL url = new URL(strUrl);
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
return urlConn;
}
}
5. 获取数据后简单的解析
我们发现获取的数据比较杂,真正有用的数据应该被包裹在soap:body里面。我们需要通过dom解析出来。同时我们发现“<”和“>”被用转移字符的形式替代了,我们还需要替换回来。这里就不贴代码了。