这是一个其实应该很常见,但是我还真是第一次遇到的问题。
源于一次接口对接。从看pdf文档(对接方只有pdf版的简介和使用手册)到整理所需要的参数都没问题。甚至一直到接口测试都平平淡淡的不出奇。知道测试结果出来我才意识到问题在哪里。
对的,他们给的接口不是常用的http,而是https。
HTTP和HTTPS的区别
HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
以上的两者的定义,接下来说两者的区别:
- https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
总体来看二者还是很有不同的。其实说这么多可能都不是需要关注的重点,重点是在程序代码里,两者是有什么区别的?
我用实际来举个例子:
你浏览器直接输入一个http的网址,回车,就进去了。不管是方法找不到还是找得到参数不对还是方法找到了参数对了进去了。反正是一样的。
可是有时候,我们访问某些网址会有一步:系统弹出个页面,告诉你该页面不一定安全,问你是否确认访问。如下图(不同浏览器的页面也是不一样的)
在这一步你只有选择了继续访问才能继续访问进去。而这种需要确认的就是https网址。而且这个还不是Https网站的证书为机构所颁发的被认证的证书(直白点说就是不是合法的证书)
比如百度这种虽是https网址,但是证书的合法的,也不会让你再确认一次的。
到这你应该知道http和https的面上的区别了。
java发送https请求
根据我上面的叙述,我们大概也知道了为啥HTTPS和http不一样。但是https和https还不一样。这里主要是有两种情况。一种是该网站的证书是被信任 的。例如百度这种。还有一种就是上文我们对接方的那种,不被信任的证书。
对了这里还有一点:因为我用的spring boot自带的RestTemplate。这个对象只支持http请求,所以发送https的不能用它。(我是说原生的RestTemplate不支持https,可以自己写实现类。但是麻烦的要死,都不如直接弃用RestTemplate)
合法证书的https
这个合法证书的https就简单的多了。和http差不了多少。用HttpsURLConnection或者 HttpURLConnection都行。
public static void main(String[] args) throws Exception{
URL serverUrl = new URL("https://xxxx");
HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-type", "application/json");
//必须设置false,否则会自动redirect到重定向后的地址
conn.setInstanceFollowRedirects(false);
conn.connect();
String result = getReturn(conn);
}
/*请求url获取返回的内容*/
public static String getReturn(HttpURLConnection connection) throws IOException{
StringBuffer buffer = new StringBuffer();
//将返回的输入流转换成字符串
try(InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, ConstantInfo.CHARSET);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);){
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
String result = buffer.toString();
return result;
}
}
不合法证书的https
这个才是今天要讲的重点,如果一个证书不合法的https要怎么用代码访问?
其实这个有三种处理办法。
- 将证书导入java的运行环境中
- 忽略证书验证过程,忽略之后任何Https协议网站皆能正常访问了,就跟第一种合法证书一样。
- java代码中加载证书,必须使用HttpsURLConnection方式
这里要说一下,这三种方式是我在网上找到的方法统计。我个人只用了第二种。因为一三都要有证书这种东西,但是我不知道啊。
主要讲一下这个忽略证书验证过程。就因为我们的浏览器有安全防护,所以在访问一些有可能危险的网站才会弹出提示说该网站危险,问是否确认访问。但是假如我们不要这个安全防护了,事先规定好了的话,就不会有确认过程了,那么http和https不就一样了么?同样代码也是一样的。接下来直接说怎么样忽略证书验证过程。
- 自己实现一个校验的类
package com.dsyl.done.tool;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
public class MyX509TrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate certificates[],String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] ax509certificate,String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
}
- 验证证书的结果是true
public static void main(String[] args) throws Exception{
SSLContext sslcontext = SSLContext.getInstance("SSL","SunJSSE");
sslcontext.init(null, new TrustManager[]{new MyX509TrustManager()}, new java.security.SecureRandom());
URL url = new URL("https://xxxx");
HostnameVerifier ignoreHostnameVerifier = new HostnameVerifier() {
public boolean verify(String s, SSLSession sslsession) {
//这块也不用有啥逻辑,确认结果是true就行
return true;
}
}; HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier); HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext.getSocketFactory());
//之后任何Https协议网站皆能正常访问
HttpsURLConnection conn = (HttpsURLConnection) serverUrl.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-type", "application/json");
//必须设置false,否则会自动redirect到重定向后的地址
conn.setInstanceFollowRedirects(false);
conn.connect();
String result = getReturn(conn);
}
//请求url获取返回的内容
public static String getReturn(HttpsURLConnection connection) throws IOException{
StringBuffer buffer = new StringBuffer();
//将返回的输入流转换成字符串
try(InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, ConstantInfo.CHARSET);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);){
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
String result = buffer.toString();
return result;
}
至此一个https的请求可以发送成功了。
这里其实我做的不太完整,因为怎么传参数我还不是很了解。恰好这个是get请求,所以我这里是直接路径拼接的参数。(我觉得自己现在贼能偷懒,哈哈)
然后反正今天的工作是顺利完成了,然后至于参数问题就先遗留着吧。
这篇文章如果稍微帮到了你记得点个喜欢点个关注呦~!也祝大家工作顺顺利利!