HttpClient对于https的支持和配置

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_22752667/article/details/52411036

网上有许多对于https的支持配置,但是对于一些新手而言,显然不够直接拿来复制粘贴然后运行出来,所以今天就将整套代码拿出来与大家分享,希望指正错误和帮我优化代码


public static DefaultHttpClient create(boolean isHttps) throws Exception{
        HttpParams params = createHttpParams();
        DefaultHttpClient httpClient = null;
        if (isHttps) {
            // 支持httphttps
            KeyStore trustStore = null;
            try {
                trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
                trustStore.load(null, null);
                SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            SchemeRegistry schemeRegistry = new SchemeRegistry();
            schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
//            schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
                schemeRegistry.register(new Scheme("https", sf, 443));
            // ThreadSafeClientConnManager线程安全管理类
            ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
            httpClient = new DefaultHttpClient(cm, params);
            } catch (Exception e) {
            }
        } else {
            httpClient = new DefaultHttpClient(params);
        }
        return httpClient;
    }

上述代码很明显是获取httpClient的实体,分为支持或者不支持https俩种,简单明了

private static class MySSLSocketFactory extends SSLSocketFactory {
    SSLContext sslContext = SSLContext.getInstance("TLS");

    public MySSLSocketFactory(KeyStore truststore)
            throws NoSuchAlgorithmException, KeyManagementException,
            KeyStoreException, UnrecoverableKeyException {
        super(truststore);

        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sslContext.init(null, new TrustManager[]{tm}, null);
    }

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

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

private static HttpParams createHttpParams() {
    final HttpParams params = new BasicHttpParams();
    // 设置是否启用旧连接检查,默认是开启的。关闭这个旧连接检查可以提高一点点性能,但是增加了I/O错误的风险(当服务端关闭连接时)。
    // 开启这个选项则在每次使用老的连接之前都会检查连接是否可用,这个耗时大概在15-30ms之间
    HttpConnectionParams.setStaleCheckingEnabled(params, false);
    HttpConnectionParams.setConnectionTimeout(params, TIMEOUT);// 设置链接超时时间
    HttpConnectionParams.setSoTimeout(params, TIMEOUT);// 设置socket超时时间
    HttpConnectionParams.setSocketBufferSize(params, SOCKET_BUFFER_SIZE);// 设置缓存大小
    HttpConnectionParams.setTcpNoDelay(params, true);// 是否不使用延迟发送(true为不延迟)
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); // 设置协议版本
    HttpProtocolParams.setUseExpectContinue(params, true);// 设置异常处理机制
    HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);// 设置编码
    HttpClientParams.setRedirecting(params, false);// 设置是否采用重定向

    ConnManagerParams.setTimeout(params, TIMEOUT);// 设置超时
    ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(MAX_CONNECTIONS));// 多线程最大连接数
    ConnManagerParams.setMaxTotalConnections(params, 10); // 多线程总连接数
    return params;
}

private static void createHttpClient(DefaultHttpClient httpClient) {
    // 添加request的拦截器,添加必要的头信息
    httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
        public void process(HttpRequest request, HttpContext context) {
            if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) {
                request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
            }
        }
    });
    // 添加response拦截器,预先对response进行一些处理
    httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
        public void process(HttpResponse response, HttpContext context) {
            final HttpEntity entity = response.getEntity();
            if (entity == null) {
                return;
            }
            final Header encoding = entity.getContentEncoding();
            if (encoding != null) {
                for (HeaderElement element : encoding.getElements()) {
                    // 如果是以GZIP压缩的数据,利用内部的填充器包装一层Gzip的流
                    if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) {
                        response.setEntity(new InflatingEntity(response.getEntity()));
                        break;
                    }
                }
            }
        }
    });
    // 设置重试次数
    httpClient.setHttpRequestRetryHandler(new HttpRetry(MAX_RETRIES));
}
/**
 * 当服务器返回的数据是以Gzip压缩的过后的数据,填充Response返回的实体数据 (Description),则返回GZIP解压流
 */
private static class InflatingEntity extends HttpEntityWrapper {
    public InflatingEntity(HttpEntity wrapped) {
        super(wrapped);
    }

    @Override
    public InputStream getContent() throws IOException {
        return new GZIPInputStream(wrappedEntity.getContent());
    }

    // 因为数据是压缩数据,所以实际长度无法估计,可以返回-1
    @Override
    public long getContentLength() {
        return -1;
    }
}
/**
 * 自定义的安全套接字协议的实现,目前采用默认的,未使用到
 */
private static class SSLSocketFactoryEx extends SSLSocketFactory {
    // 此类的实例表示安全套接字协议的实现,它充当用于安全套接字工厂或 SSLEngine 的工厂。用可选的一组密钥和信任管理器及安全随机字节源初始化此类。
    SSLContext sslContext = SSLContext.getInstance("TLS");

    public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(truststore);
        // TrustManager负责管理做出信任决定时使用的的信任材料,也负责决定是否接受同位体提供的凭据。
        // X509TrustManager此接口的实例管理使用哪一个 X509 证书来验证远端的安全套接字。决定是根据信任的证书授权、证书撤消列表、在线状态检查或其他方式做出的。
        TrustManager tm = new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return null;// 返回受验证同位体信任的认证中心的数组。
            }

            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                // 给出同位体提供的部分或完整的证书链,构建到可信任的根的证书路径,并且返回是否可以确认和信任将其用于基于验证类型的客户端 SSL 验证。
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                // 给出同位体提供的部分或完整的证书链,构建到可信任的根的证书路径,并且返回是否可以确认和信任将其用于基于验证类型的服务器 SSL 验证。
            }
        };
        sslContext.init(null, new TrustManager[]{tm}, null);
    }

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

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}
注释已经很清楚了,如有疑问请留言,那么我们如何使用这些看似很费解的代码呢,下面就以下载https开头的URL地址的文件来模拟实战,也就是APK的下载更新,希望对大家有帮助。

首先,我们需要一个UpDateManager,默认使用单例模式。

public static UpDateManager getUpDateManager(Context context, Handler handler, ProgressDialog pBar) {
    if (upDateManager == null) {
        //防止内部代码
        //线程不安全
        synchronized (UpDateManager.class) {
            if (upDateManager == null) {
                upDateManager = new UpDateManager(context, handler, pBar);
            }
        }
    }
    return upDateManager;

}

handler和pbar是为了告诉主线程显示下载进度
private boolean isStop = true;

public boolean isStop() {
    return isStop;
}

public void setIsStop(boolean isStop) {
    if (!isStop) {
        FileUtils.deleteFile(SDPATH + fileName);

    }
    this.isStop = isStop;
}

阻止下载,并删除为完成下载的文件,
public void downFile(final String url) {
        if (pBar != null) {
            pBar.show();

        }
        new Thread() {
            public void run() {

                try {
                    AbstractHttpClient client = HttpClientFactory.create(true);
                    HttpGet get = new HttpGet(url);
                    HttpResponse response;
                    response = client.execute(get);
                    HttpEntity entity = response.getEntity();
                    long length = entity.getContentLength();
                    InputStream is = entity.getContent();
                    Log.e("liushun", "length...." + length);
//                    FileUtils.writeFile(is, FileUtils.getExternalStoragePath()
//                            + ".kg-gold.com" + "Download" + url, false);
                    FileOutputStream fileOutputStream = null;
                    if (is != null) {
//                        FileUtils.writeFile(is, FileUtils.getExternalStoragePath()
//                                + ".kg-gold.com" + "Download" + url, false);
//                        File file = new File(
//                                Environment.getExternalStorageDirectory(),
//                                fileName);
                        FileUtils.deleteFile(SDPATH + fileName);
                        File file = FileUtils.creatSDFile(fileName);
                        fileOutputStream = new FileOutputStream(file);
                        byte[] buf = new byte[1024];
                        int ch = -1;
                        long count = 0;
                        while ((ch = is.read(buf)) != -1 && isStop) {
                            fileOutputStream.write(buf, 0, ch);
                            count += ch;

                            if (length > 0) {
                                if (pBar != null) {
                                    downProcess = count * 100 / length + "";
                                    Message msg = Message.obtain();
                                    msg.obj = downProcess;
                                    msg.what = 55;
                                    handler.sendMessage(msg);


                                }
                                Log.e("liushun", "count%..." + downProcess);

                            }
                        }
                    }
                    if (isStop) {
                        fileOutputStream.flush();
                        if (fileOutputStream != null) {
                            fileOutputStream.close();
                        }
                        down();
                    }

                } catch (ClientProtocolException e) {
                    //下载失败
                    e.printStackTrace();
                } catch (IOException e) {
                    //下载失败
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
这是下载的核心代码,
 AbstractHttpClient client = HttpClientFactory.create(true); 是创建支持https的HttpClent

void update() {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(Uri.fromFile(new File(Environment
                    .getExternalStorageDirectory(), fileName)),
            "application/vnd.android.package-archive");
    context.startActivity(intent);
}
下载完成,然后触发系统的安装流程。



展开阅读全文

没有更多推荐了,返回首页