android httpClient 支持HTTPS的访问方式
发布日期:2018-05-04最近项目需要用到httpClient走HTTPS的访问方式进行数据传输,在度娘与谷哥大神的帮助下,结论出了以下做法,提出来给需要的人,技术上就不多说了自己查了
环境:android 4.4 api 19
帮助:
- 低版本下(4.x或更低)开放TLSv1.1/TLSv1.2功能
- 解决net.ssl.SSLPeerUnverifiedException: No peer certificate...
1.创建class
importorg.apache.http.HttpVersion; importorg.apache.http.conn.ClientConnectionManager; importorg.apache.http.conn.params.ConnManagerPNames; importorg.apache.http.conn.params.ConnPerRouteBean; importorg.apache.http.conn.scheme.PlainSocketFactory; importorg.apache.http.conn.scheme.Scheme; importorg.apache.http.conn.scheme.SchemeRegistry; importorg.apache.http.conn.ssl.SSLSocketFactory; importorg.apache.http.impl.client.DefaultHttpClient; importorg.apache.http.impl.conn.SingleClientConnManager; importorg.apache.http.params.BasicHttpParams; importorg.apache.http.params.HttpConnectionParams; importorg.apache.http.params.HttpParams; importorg.apache.http.params.HttpProtocolParams; importorg.apache.http.protocol.HTTP; importjava.io.IOException; importjava.net.Socket; importjava.net.UnknownHostException; importjava.security.KeyManagementException; importjava.security.KeyStore; importjava.security.KeyStoreException; importjava.security.NoSuchAlgorithmException; importjava.security.UnrecoverableKeyException; importjava.security.cert.X509Certificate; importjavax.net.ssl.SSLContext; importjavax.net.ssl.SSLSocket; importjavax.net.ssl.TrustManager; importjavax.net.ssl.X509TrustManager; publicclass SSLSocketFactoryEx extends SSLSocketFactory { public final static int TIME_OUT_DELAY =20000; SSLContext sslContext =SSLContext.getInstance("TLS"); public SSLSocketFactoryEx(KeyStoretruststore) throws NoSuchAlgorithmException,KeyManagementException, KeyStoreException,UnrecoverableKeyException { super(truststore); initSSLContext(); } TrustManager tm = new X509TrustManager() { @Override public X509Certificate[]getAcceptedIssuers() { // TODO Auto-generated method stub return null; } @Override public void checkClientTrusted( java.security.cert.X509Certificate[]chain, String authType) throwsjava.security.cert.CertificateException {} @Override public void checkServerTrusted( java.security.cert.X509Certificate[] chain, String authType) throwsjava.security.cert.CertificateException {} }; @Override public Socket createSocket(Socket socket,String host, int port, boolean autoClose) throws IOException,UnknownHostException { SSLSocket sslSocket=(SSLSocket)sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); sslSocket.setEnabledProtocols(newString[]{"TLSv1.2"}); return sslSocket; } private void initSSLContext() { try { // 既然是跳过认证,我们把没有的都填null,此时发现第二个参数是一个数组,那么意思就是我们可以放多个证书认证; sslContext.init(null, newTrustManager[] { tm }, null); } catch (KeyManagementException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static DefaultHttpClientgetNewHttpClient() { try { // 查看API这里可以得到一个默认的Type. KeyStore truststore =KeyStore.getInstance(KeyStore .getDefaultType()); truststore.load(null, null); // 这里发现需要一个KeyStore,那么我们就在上面New一个KeyStore,这是一个密钥库,查看API发现能直接getInstance得到对象; SSLSocketFactory factory = newSSLSocketFactoryEx(truststore); // 这里就是我们最需要的也是最关键的一步,设置主机认证,通过API发现有一个常量就是允许所有认证通过。 factory.setHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER); // 实现Httpprams的子类 HttpParams params = newBasicHttpParams(); params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS,30); params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, newConnPerRouteBean(30)); params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false); //通过Http适配器设置必要参数,现在通用HTTP1.1协议,和UTF-8字符。 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); //通过适配器设置连接参数,等待时间和,连接时间 HttpConnectionParams.setSoTimeout(params, TIME_OUT_DELAY); HttpConnectionParams.setConnectionTimeout(params, TIME_OUT_DELAY); // 同样New出来,查看API,需要我们注册一个计划,来封装协议细节 SchemeRegistry schreg = newSchemeRegistry(); // 最后一个参数是端口设置,Https常用的端口就是443。 schreg.register(newScheme("https", factory, 443)); // 既然是工具类,这里也把http协议加上,中间的协议工厂我们就用简单的PlainSocketFactory,这里可以通过API查看到,端口就用常用的80端口(默认) schreg.register(newScheme("http", PlainSocketFactory.getSocketFactory(), 80)); // ClientConnectionManager是一个借口,就实现他的子类,同样需要2个参数,第一个我们熟悉,第二个就是让我们自定义自己的一套方案协议,继续在上面一步一步完成; ClientConnectionManager conman =new SingleClientConnManager( params, schreg); // 返回我们需要的一个默认Httpclient,为了把之前做的关联起来,就new最多参数的构造函数,需要2个参数,Httpparams是我们熟悉的, // 发现ClientConnectionManager不太熟悉,通过API发现这是客服端连接管理者,既然这样,就在上面一步一步完成。 return newDefaultHttpClient(conman, params); } catch (Exception e) { // TODO: handle exception } return new DefaultHttpClient(); } }
2.应用上
//for https HttpClient httpClient =SSLSocketFactoryEx.getNewHttpClient(); //設定參數 httpClient.getParams().setIntParameter(HttpConnectionParams.SO_TIMEOUT,TIME_OUT_DELAY); httpClient.getParams().setIntParameter(HttpConnectionParams.CONNECTION_TIMEOUT,TIME_OUT_DELAY); HttpPost httpPost = new HttpPost(EndpointURL); //添加http头信息 httpPost.addHeader("xxx...",xxx...); //json數據 StringEntitystringEntity = new StringEntity(jsonString); stringEntity.setContentType("application/json;charset=UTF-8"); stringEntity.setContentEncoding(newBasicHeader(HTTP.CONTENT_TYPE,"application/json;charset=UTF-8")); httpPost.setEntity(stringEntity); //回傳服務查詢結果(json) httpResponse =httpClient.execute(httpPost);
本文转自CSDN博客