最近公司将所有的接口请求方式改为了Https,所以在这记录分享一下。
一、Https有什么优势和劣势。
优势:
1、使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
2、HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。
3、HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。
劣势:
1、SSL 证书需要钱。功能越强大的证书费用越高。个人网站、小网站没有必要一般不会用。
2、SSL 证书通常需要绑定 IP,不能在同一 IP 上绑定多个域名。IPv4 资源不可能支撑这个消耗。( SSL 有扩展可以部分解决这个问题,但是比较麻烦,而且要求浏览器、操作系统支持。Windows XP 就不支持这个扩展,考虑到 XP 的装机量,这个特性几乎没用。)
3、HTTPS 连接缓存不如 HTTP 高效,大流量网站如非必要也不会采用。流量成本太高。
4、HTTPS 连接服务器端资源占用高很多,支持访客稍多的网站需要投入更大的成本。如果全部采用 HTTPS,基于大部分计算资源闲置的假设的 VPS 的平均成本会上去。
5、HTTPS 协议握手阶段比较费时,对网站的相应速度有负面影响。如非必要,没有理由牺牲用户体验。
结论:所以Https并不是适用于所有的情况,也不是一定是比http好,所以使用前需要慎重。
二、准备工作
1.cer证书
三、示例代码
package com.zeepson.smartbox.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.KeyManagerFactory;
import android.util.Log;
import com.zeepson.smartbox.service.ZeepsonApplication;
public class MyHttpPost {
public static String sendPost(String stringUrl, String params) {
byte[] bytes = params.toString().getBytes();
try {
URL url = new URL(stringUrl);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
// 读取服务器要验证的cer证书
connection.setSSLSocketFactory(setCertificates(ZeepsonApplication.getContext().getAssets().open("server.cer")));
// 设置不验证服务器,返回true不验证,false为验证,默认为false;也可以根据arg0的值验证或不验证指定服务器;
connection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
connection.setConnectTimeout(30000);
connection.setDoInput(true);// 打开输入流,默认情况下是true
connection.setDoOutput(true);// 打开输出流 ,需要设为true, 默认情况下是false
connection.setRequestMethod("POST");
connection.setUseCaches(false);// 使用post方式不能使用缓存
// 设置请求体类型为文本类型
connection.setRequestProperty("Content-Type", "application/json");
// 设置请求体 的长度
connection.setRequestProperty("Content-Length", String.valueOf(bytes.length));
// 获得输出流,向服务器写入
// getOutputStream会隐含的进行connect,所以不用调用connect也可以
OutputStream outputStream = connection.getOutputStream();
outputStream.write(bytes);
int response = connection.getResponseCode();// 获取响应码
Log.i("-------新httpPost响应码*********************", ">>>>>>>>>>>>" + response);
if (response == HttpURLConnection.HTTP_OK) {
InputStream inputStream = connection.getInputStream();// 获取输入流
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
return responseResult(br);// 处理接收到的数据
}
} catch (Exception e) {
e.printStackTrace();
return "{\"type\":\"error\",\"code\":0,\"message\":\"发送请求出现错误\",\"data\":null}";
}
return "{\"type\":\"error\",\"code\":0,\"message\":\"连接超时\",\"data\":null}";
}
private static String responseResult(BufferedReader br) {
String line = null;
StringBuffer sb_response = new StringBuffer();
try {
while ((line = br.readLine()) != null) {
sb_response.append(line);
}
} catch (Exception e) {
e.printStackTrace();
}
String ret = new String(sb_response);
Log.i("----------------服务器返回值--------------", ret + "");
return ret;
}
public static SSLSocketFactory setCertificates(InputStream... certificates){
try{
//证书工厂。此处指明证书的类型
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
//创建一个证书库
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certificate : certificates){
String certificateAlias = Integer.toString(index++);
//将证书导入证书库
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
try{
if (certificate != null)
certificate.close();
} catch (IOException e){
e.printStackTrace() ;
}
}
//取得SSL的SSLContext实例
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.
getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
//初始化keystore
KeyStore clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(ZeepsonApplication.getContext().getAssets().open("client1.bks"), "123456".toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, "123456".toCharArray());
// 第一个参数是授权的密钥管理器,用来授权验证。TrustManager[]第二个是被授权的证书管理器,用来验证服务器端的证书。第三个参数是一个随机数值,可以填写null
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
return sslContext.getSocketFactory() ;
} catch (Exception e){
e.printStackTrace();
}
return null ;
}
}
结尾:这次只用到了单向验证,下次需要双向验证后面会补上。