OKHTTP默认是支持通过CA认证的HTTPS请求的,例如利用get请求去获得Https://www.baidu.com/的信息是可以直接拿到的。
但是对于没有通过CA认证的网站,OKHTTP是无法进行HTTPS请求获取数据的,例如获取12306网站的数据:https://kyfw.12306.cn/otn/
所以需要进行证书信任才能正常的进行访问,在OKHTTP的WIKI中就已经介绍了如何使用HTTPS进行通信。
HTTPS在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息。握手过程的简单描述如下:
握手过程中如果有任何错误,都会使加密连接断开,从而阻止了隐私信息的传输。
srca.cer,并放在Assets文件夹中。
public final class HTTPSUtils {
private OkHttpClient client;
public Context mContext;
/**
* 初始化HTTPS,添加信任证书
* @param context
*/
public HTTPSUtils(Context context) {
mContext = context;
X509TrustManager trustManager;
SSLSocketFactory sslSocketFactory;
final InputStream inputStream;
try {
inputStream = mContext.getAssets().open("srca.cer"); // 得到证书的输入流
try {
trustManager = trustManagerForCertificates(inputStream);//以流的方式读入证书
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{trustManager}, null);
sslSocketFactory = sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
client = new OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.build();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 测试代码
* @throws Exception
*/
public void run() throws Exception {
Request request = new Request.Builder()
.url("https://kyfw.12306.cn/otn/")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0; i < responseHeaders.size(); i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
}
});
}
/**
* 以流的方式添加信任证书
*/
/**
* Returns a trust manager that trusts {@code certificates} and none other. HTTPS services whose
* certificates have not been signed by these certificates will fail with a {@code
* SSLHandshakeException}.
*
*
This can be used to replace the host platform's built-in trusted certificates with a custom
* set. This is useful in development where certificate authority-trusted certificates aren't
* available. Or in production, to avoid reliance on third-party certificate authorities.
*
*
*
Warning: Customizing Trusted Certificates is Dangerous!
*
*
Relying on your own trusted certificates limits your server team's ability to update their
* TLS certificates. By installing a specific set of trusted certificates, you take on additional
* operational complexity and limit your ability to migrate between certificate authorities. Do
* not use custom trusted certificates in production without the blessing of your server's TLS
* administrator.
*/
private X509TrustManager trustManagerForCertificates(InputStream in)
throws GeneralSecurityException {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Collection extends Certificate> certificates = certificateFactory.generateCertificates(in);
if (certificates.isEmpty()) {
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
}
// Put the certificates a key store.
char[] password = "password".toCharArray(); // Any password will work.
KeyStore keyStore = newEmptyKeyStore(password);
int index = 0;
for (Certificate certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificate);
}
// Use it to build an X509 trust manager.
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}
return (X509TrustManager) trustManagers[0];
}
/**
* 添加password
* @param password
* @return
* @throws GeneralSecurityException
*/
private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); // 这里添加自定义的密码,默认
InputStream in = null; // By convention, 'null' creates an empty key store.
keyStore.load(in, password);
return keyStore;
} catch (IOException e) {
throw new AssertionError(e);
}
}
}
HTTPSUtils customTrust = new HTTPSUtils(this);
try {
customTrust.run();
} catch (Exception e) {
e.printStackTrace();
}
最后输出的信息:
06-15 08:54:01.728 5913-5926/? I/System.out: Date: Wed, 15 Jun 2016 12:54:03 GMT
06-15 08:54:01.728 5913-5926/? I/System.out: Server: Apache-Coyote/1.1
06-15 08:54:01.728 5913-5926/? I/System.out: X-Powered-By: Servlet 2.5; JBoss-5.0/JBossWeb-2.1
06-15 08:54:01.728 5913-5926/? I/System.out: Set-Cookie: JSESSIONID=0A01D727FCF585CB10CC82BB7CAB47A3A505745087; Path=/otn
06-15 08:54:01.728 5913-5926/? I/System.out: ct: c1_39
06-15 08:54:01.728 5913-5926/? I/System.out: Content-Type: text/html;charset=utf-8
06-15 08:54:01.728 5913-5926/? I/System.out: Content-Language: zh-CN
06-15 08:54:01.728 5913-5926/? I/System.out: Transfer-Encoding: chunked
06-15 08:54:01.728 5913-5926/? I/System.out: Set-Cookie: BIGipServerotn=668401930.64545.0000; path=/
06-15 08:54:01.728 5913-5926/? I/System.out: X-Via: 1.1 hljshwt42:9 (Cdn Cache Server V2.0)
06-15 08:54:01.728 5913-5926/? I/System.out: Connection: keep-alive
06-15 08:54:01.728 5913-5926/? I/System.out: X-Cdn-Src-Port: 58011
06-15 08:54:01.776 5913-5926/? I/System.out:
06-15 08:54:01.788 5913-5926/? I/System.out:
06-15 08:54:01.788 5913-5926/? I/System.out:
06-15 08:54:01.788 5913-5926/? I/System.out:
06-15 08:54:01.788 5913-5926/? I/System.out:
06-15 08:54:01.788 5913-5926/? I/System.out:
06-15 08:54:01.800 5913-5926/? I/System.out: