android httpClient(https/http)的優化構建方式一

參考:基於java的https雙向認證,android上亦可用java

Android Https相關徹底解析 當OkHttp遇到Https
android


在android中,常常不可避免的的使用https和http訪問網絡數據,所以須要先構建一個網絡訪問clientapache

其中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是請求失敗後重試的規則app

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來支持全部主機經過socket

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同樣。ide


對於https安全請求的的加密過程,咱們須要充分的認識,簡單的說他是一個加密的過程。this

對於這個過程的請求才叫安全請求,那麼這個請求是怎麼構建的呢加密

通常來講證書放在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();
    }
  //  ......
  
  }
相關文章
相關標籤/搜索