android httpClient(https/http)的优化构建方式一

参考:基于java的https双向认证,android上亦可用

Android Https相关完全解析 当OkHttp遇到Https


在android中,经常不可避免的的使用https和http访问网络数据,因此需要先构建一个网络访问client

其中https的访问需要使用SSLSocket,但对于一般安全性要求不是很高的通信,一般设置SSLSocket是允许所有主机通过,下面给出2中,一种是允许所有主机通过的https通信,另一种是加密传输,需要使用cert证书。

允许所有主机通过

public class GlobalUtils
{
    
     public static HttpClient getAndroidHttpClient(int connTimeout, String userAgent,int retryTimes)
     {
              AbstractHttpClient httpClient = null;
	      //设置请求控制参数
	      HttpParams params = new BasicHttpParams();
	      ConnManagerParams.setTimeout(params, connTimeout);
	      HttpConnectionParams.setSoTimeout(params, connTimeout);
	      HttpConnectionParams.setConnectionTimeout(params, connTimeout);

	        if (TextUtils.isEmpty(userAgent)) {
	            userAgent = System.getProperty("http.agents", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36");
	        }
	        HttpProtocolParams.setUserAgent(params, userAgent);
               //设置最大的连接数
	        ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(10));
	        ConnManagerParams.setMaxTotalConnections(params, 10);

	        HttpConnectionParams.setTcpNoDelay(params, true); //关闭Socket缓冲

	        HttpConnectionParams.setSocketBufferSize(params, 1024 * 8);//本方法与setTcpNoDelay冲突

	        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);

	        SchemeRegistry schemeRegistry = new SchemeRegistry();
	        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
	        schemeRegistry.register(new Scheme("https", DefaultSSLSocketFactory.getSocketFactory(), 443));

	        httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager(params, schemeRegistry), params);
	        httpClient.setHttpRequestRetryHandler(new RetryHandler(retryTimes));

	        httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
	            @Override
	            public void process(org.apache.http.HttpRequest httpRequest, HttpContext httpContext) throws org.apache.http.HttpException, IOException {
	                if (!httpRequest.containsHeader("Accept-Encoding")) {
	                    httpRequest.addHeader("Accept-Encoding", "gzip");
	                }
	            }
	        });

	        httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
	            @Override
	            public void process(HttpResponse response, HttpContext httpContext) throws org.apache.http.HttpException, IOException {
	                final HttpEntity entity = response.getEntity();
	                if (entity == null) {
	                    return;
	                }
	                final Header encoding = entity.getContentEncoding();
	                if (encoding != null) {
	                    for (HeaderElement element : encoding.getElements()) {
	                        if (element.getName().equalsIgnoreCase("gzip")) {
	                            response.setEntity(new GZipDecompressingEntity(response.getEntity()));
	                            return;
	                        }
	                    }
	                }
	            }
	        });
			return httpClient;
	    }

}

上面的重试RetryHandler是请求失败后重试的规则

public class RetryHandler implements HttpRequestRetryHandler {  //需要实现HttpRequestRetryHandler

    private static final int RETRY_SLEEP_INTERVAL = 500;

    private static HashSet<Class<?>> exceptionWhiteList = new HashSet<Class<?>>();

    private static HashSet<Class<?>> exceptionBlackList = new HashSet<Class<?>>();

    static {
        exceptionWhiteList.add(NoHttpResponseException.class);
        exceptionWhiteList.add(UnknownHostException.class);
        exceptionWhiteList.add(SocketException.class);

        exceptionBlackList.add(InterruptedIOException.class);
        exceptionBlackList.add(SSLHandshakeException.class);
    }

    private final int maxRetries;

    public RetryHandler(int maxRetries) {
        this.maxRetries = maxRetries;
    }

    @Override
    public boolean retryRequest(IOException exception, int retriedTimes, HttpContext context) {
        boolean retry = true;

        if (exception == null || context == null) {
            return false;
        }

        Object isReqSent = context.getAttribute(ExecutionContext.HTTP_REQ_SENT);
        boolean sent = isReqSent == null ? false : (Boolean) isReqSent;

        if (retriedTimes > maxRetries) {
            retry = false;
        } else if (exceptionBlackList.contains(exception.getClass())) {
            retry = false;
        } else if (exceptionWhiteList.contains(exception.getClass())) {
            retry = true;
        } else if (!sent) {
            retry = true;
        }

        if (retry) {
            try {
                Object currRequest = context.getAttribute(ExecutionContext.HTTP_REQUEST);
                if (currRequest != null) {
                //这里只允许GET请求的重试,因为在一般访问中POST重试会造成重复提交问题,因此不宜使用
                    if (currRequest instanceof HttpRequestBase) {
                        HttpRequestBase requestBase = (HttpRequestBase) currRequest;
                        retry = "GET".equals(requestBase.getMethod());
                    } else if (currRequest instanceof RequestWrapper) {
                        RequestWrapper requestWrapper = (RequestWrapper) currRequest;
                        retry = "GET".equals(requestWrapper.getMethod());
                    }
                } else {
                    retry = false;
                    LogUtils.e("retry error, curr request is null");
                }
            } catch (Throwable e) {
                retry = false;
                LogUtils.e("retry error", e);
            }
        }

        if (retry) {
            SystemClock.sleep(RETRY_SLEEP_INTERVAL); // sleep a while and retry http request again.
        }

        return retry;
    }

}

需要重写SSLSocketFactory来支持所有主机通过

public class DefaultSSLSocketFactory extends SSLSocketFactory {
    //ssl上下文环境
    private SSLContext sslContext = SSLContext.getInstance("TLS");
    //证书保存对象
    private static KeyStore trustStore;

    static {
        try {
            trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            //通常这里需要加载证书
            trustStore.load(null, null);
        } catch (Throwable e) {
           e.printStackTrace();
        }
    }

    private static DefaultSSLSocketFactory instance;

    public static DefaultSSLSocketFactory getSocketFactory() {
        if (instance == null) {
            try {
                instance = new DefaultSSLSocketFactory();
            } catch (Throwable e) {
                LogUtils.e(e.getMessage(), e);
            }
        }
        return instance;
    }

    private DefaultSSLSocketFactory()
            throws UnrecoverableKeyException,
            NoSuchAlgorithmException,
            KeyStoreException,
            KeyManagementException {
        super(trustStore);

        TrustManager trustAllCerts = new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] chain, String authType)
                    throws java.security.cert.CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] chain, String authType)
                    throws java.security.cert.CertificateException {
            }
        };
        //初始化509凭证信任管理器
        sslContext.init(null, new TrustManager[]{trustAllCerts}, null);
        //设置所有请求都会得到客户端的信任
        this.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
        //连接SSL Socket
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

当然上面的通信谈不上SSL加密,因此使用了https和没使用https请求没啥区别,就像http一样。


对于https安全请求的的加密过程,我们需要充分的认识,简单的说他是一个加密的过程。

android httpClient(https/http)的优化构建方式一

对于这个过程的请求才叫安全请求,那么这个请求是怎么构建的呢

一般来说证书放在assets或者raw资源文件下(以下代码来自互联网,用户可以再第一段代码中稍作修改,便可使用)

public void getHttpsKeyStore(){
    AssetManager am = context.getAssets(); 
    InputStream ins = am.open("robusoft.cer"); 
    try {
            //读取证书
            CertificateFactory cerFactory = CertificateFactory.getInstance("X.509");  //问1
            Certificate cer = cerFactory.generateCertificate(ins);
            //创建一个证书库,并将证书导入证书库
            KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");   //问2
            keyStore.load(null, null);
            keyStore.setCertificateEntry("trust", cer);
            return keyStore;
    } finally {
            ins.close();
    }
  
}

将这里代码整合到第一段代码中,形成https安全请求,当然也可以单独使用,

public static HttpClient getAndroidHttpClient(int connTimeout, String userAgent,int retryTimes)
{
//......
   AssetManager am = context.getAssets(); 
    InputStream ins = am.open("robusoft.cer"); 
    try {
            //读取证书
            CertificateFactory cerFactory = CertificateFactory.getInstance("X.509");  //问1
            Certificate cer = cerFactory.generateCertificate(ins);
            //创建一个证书库,并将证书导入证书库
            KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");   //问2
            keyStore.load(null, null);
            keyStore.setCertificateEntry("trust", cer);
             //把咱的证书库作为信任证书库
            SSLSocketFactory socketFactory = new SSLSocketFactory(keystore);
            schemeRegistry.register(new Scheme("https", socketFactory , 443));
    } finally {
            ins.close();
    }
  //  ......
  
  }


你可能感兴趣的:(android httpClient(https/http)的优化构建方式一)