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

来源:互联网 发布:淘宝如何好评返现 编辑:程序博客网 时间:2024/05/16 17:24

转载自http://my.oschina.net/ososchina/blog/339172

摘要 android中经常使用的网络请求是超文本网络请求,http和https,http代表了大众的请求方式,https是ssl通信,https请求需要服务端和客户端反反复复的验证和加密

参考:基于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安全请求的的加密过程,我们需要充分的认识,简单的说他是一个加密的过程。

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

一般来说证书放在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();    }  //  ......  }
0 0
原创粉丝点击