您当前的位置: 首页 >  http

小枫_S

暂无认证

  • 7浏览

    0关注

    42博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

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

小枫_S 发布时间:2016-04-25 16:59:07 ,浏览量:7

转载自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>();

    private static HashSet>();

    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();
    }
  //  ......

  }
关注
打赏
1495089800
查看更多评论
立即登录/注册

微信扫码登录

0.0466s