`
m635674608
  • 浏览: 5060336 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

android httpClient 支持HTTPS的2种处理方式

 
阅读更多

问题:

项目中Android https或http请求地址重定向为HTTPS的地址,相信很多人都遇到了这个异常(无终端认证):
 javax.net.ssl.SSLPeerUnverifiedException: No peer certificate

 

 

解决过程:

1.没遇到过的问题,搜索吧,少年

log里出现这个异常,作者第一次遇到,不知道啥意思。看下字面意思,是ssl协议中没有终端认证。SSL?作者没用到ssl协议呀,只是通过httpClient请求一个重定向https的地址。
好吧,google下,知道了个差不多情况的帖子,http://www.eoeandroid.com/thread-161747-1-1.html。恩恩,一个不错的帖子,给出了个解决方案。照着来试下。添加个继承SSLSocketFactory的
自定义类。并在初始化httpclient支持https时,注册进去。看下面代码:

 

public classHttpClientHelper{

	private static HttpClient httpClient;

	privateHttpClientHelper(){
	}

	publicstaticsynchronized HttpClient getHttpClient(){

		if (null == httpClient) {
			// 初始化工作
			try {
				KeyStore trustStore = KeyStore.getInstance(KeyStore
						.getDefaultType());
				trustStore.load(null, null);
				SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore);
				sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);  //允许所有主机的验证

				HttpParams params = new BasicHttpParams();

				HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
				HttpProtocolParams.setContentCharset(params,
						HTTP.DEFAULT_CONTENT_CHARSET);
				HttpProtocolParams.setUseExpectContinue(params, true);

				// 设置连接管理器的超时
				ConnManagerParams.setTimeout(params, 10000);
				// 设置连接超时
				HttpConnectionParams.setConnectionTimeout(params, 10000);
				// 设置socket超时
				HttpConnectionParams.setSoTimeout(params, 10000);

				// 设置http https支持
				SchemeRegistry schReg = new SchemeRegistry();
				schReg.register(new Scheme("http", PlainSocketFactory
						.getSocketFactory(), 80));
				schReg.register(new Scheme("https", sf, 443));

				ClientConnectionManager conManager = new ThreadSafeClientConnManager(
						params, schReg);

				httpClient = new DefaultHttpClient(conManager, params);
			} catch (Exception e) {
				e.printStackTrace();
				return new DefaultHttpClient();
			}
		}
		return httpClient;
	}

}

classSSLSocketFactoryExextendsSSLSocketFactory{

	SSLContext sslContext = SSLContext.getInstance("TLS");

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

		TrustManager tm = new X509TrustManager() {

			@Override
			public java.security.cert.X509Certificate[] getAcceptedIssuers() {
				return null;
			}

			@Override
			publicvoidcheckClientTrusted(
					java.security.cert.X509Certificate[] chain, String authType)throws java.security.cert.CertificateException {

			}

			@Override
			publicvoidcheckServerTrusted(
					java.security.cert.X509Certificate[] chain, String authType)throws java.security.cert.CertificateException {

			}
		};

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

ok,run下,狂乱的点到测试按钮,深吸口气,盯着eclipse中的logat。咦?神奇的竟然没有报之前的 javax.net.ssl.SSLPeerUnverifiedException: No peer certificate的异常了。服务端的数据正常返回了。,狂喜中...

 

2.了解并分析问题

狂喜中,得分析这问题诶。不然老大来问,啥情况?楞半天不知道咋说(作者就经常这样,所以吸取教训。所以的弄懂出现的问题,学习+汇报工作)。
思来想去,就是作者请求的是一个重定向https的地址。好吧,那就学习下https(之前被老大深深的教过,http就是request/response)。继续搜索吧,少年。下面总结下学习到的https知识。

2.1 https

 

HTTPS:超文本安全传输协议,和HTTP相比,多了一个SSL/TSL的认证过程,端口为443。(鄙视下之前说的)

作者没用到ssl协议呀,只是通过httpClient请求一个重定向https的地址

 

1.peer终端发送一个request,https服务端把支持的加密算法等以证书的形式返回一个身份信息(包含ca颁发机构和加密公钥等)。

2.获取证书之后,验证证书合法性。

3.随机产生一个密钥,并以证书当中的公钥加密。

4.request https服务端,把用公钥加密过的密钥传送给https服务端。

5.https服务端用自己的密钥解密,获取随机值。

6.之后双方传送数据都用此密钥加密后通信。

看下面一张网上的得来的https的时序图:

 

 

2.2分析下出现问题的原因

 

好吧,大概的流程知道了。定位已经非常清楚了。在第2步验证证书时,无法验证。为啥无法验证呢?没有添加信任。详细参考下

http://www.cnblogs.com/P_Chou/archive/2010/12/27/https-ssl-certification.html讲的非常清楚https-ssl的认证过程,膜拜下该作者

 

这样想来,上面提供的解决方案就是添加默认信任全部证书。以此来通过接下来的通信。

3.解决问题

但是,这样问题是解决了。但是觉得还是不带靠谱(信任全部证书有点危险)。继续噼噼啪啪的网上搜索一番。又找到了一种解决方案,其过程大致这样的:

1.浏览器访问https地址,保存提示的证书到本地,放到android项目中的assets目录。

2.导入证书,代码如下。

3.把证书添加为信任。

 

String requestHTTPSPage(String mUrl) {
		InputStream ins = null;
		String result = "";
		try {
			ins = context.getAssets().open("app_pay.cer"); //下载的证书放到项目中的assets目录中
			CertificateFactory cerFactory = CertificateFactory
					.getInstance("X.509");
			Certificate cer = cerFactory.generateCertificate(ins);
			KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
			keyStore.load(null, null);
			keyStore.setCertificateEntry("trust", cer);

			SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore);
			Scheme sch = new Scheme("https", socketFactory, 443);
			HttpClient mHttpClient = new DefaultHttpClient();
			mHttpClient.getConnectionManager().getSchemeRegistry()
					.register(sch);

			BufferedReader reader = null;
			try {
				Log.d(TAG, "executeGet is in,murl:" + mUrl);
				HttpGet request = new HttpGet();
				request.setURI(new URI(mUrl));
				HttpResponse response = mHttpClient.execute(request);
				if (response.getStatusLine().getStatusCode() != 200) {
					request.abort();
					return result;
				}

				reader = new BufferedReader(new InputStreamReader(response
						.getEntity().getContent()));
				StringBuffer buffer = new StringBuffer();
				String line = null;
				while ((line = reader.readLine()) != null) {
					buffer.append(line);
				}
				result = buffer.toString();
				Log.d(TAG, "mUrl=" + mUrl + "\nresult = " + result);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (reader != null) {
					reader.close();
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			try {
				if (ins != null)
					ins.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}

 

接着,验证下呗。吼吼,稀里糊涂的又可以了。感动的泪流满面。

 

最后总结:

 

2种方法都解决了作者遇到的问题,这里记录下。以防下次遇到,希望能给遇到相同问题朋友有所参考帮助。

 

https://my.oschina.net/blackylin/blog/144136

分享到:
评论

相关推荐

    Android HttpClient用到的jar包

    2. **Httpmime**:这是Apache HttpClient的一个扩展,主要添加了对MIME类型的处理支持,包括文件上传。`httpmime-4.0.jar`包含了`MultipartEntity`类,这个类是实现文件上传的核心,允许我们构建一个包含多个部分的...

    Android HttpClient工具类

    此外,由于Android系统的限制,从API Level 19开始,HttpClient默认不再支持SSL。如果需要与HTTPS服务器通信,需要自定义SSLSocketFactory。 总之,Android HttpClient提供了一套完整的HTTP通信框架,允许开发者...

    struts2 android httpclient 上传文件

    Struts2、Android和HttpClient是三个关键的技术领域,它们在本次文件上传的场景中相互结合。Struts2是一个流行的Java Web框架,用于构建MVC(模型-视图-控制器)结构的应用程序。Android是Google开发的移动操作系统...

    Android Httpclient Proxy Test

    总之,Android中的HttpClient虽然在新版本中被弃用,但它仍然是一种有效的工具,尤其是在处理复杂的网络请求和代理设置时。通过理解HttpClient的配置、代理设置、请求发起、响应处理和异常管理,你可以有效地实现...

    android HttpClient

    虽然面临被替代的命运,但在某些情况下,如对低版本Android的支持和需要高级功能时,它仍然是一种实用的选择。结合Android_HTTP服务实例.docx,可以更深入地了解如何在实际项目中应用这些概念。

    android httpClient所需jar包

    3. **httpclient-4.5.6.jar**: 这是HttpClient的较新版本,相对于commons-httpclient,它有更多改进和优化,包括更好的性能、更完善的错误处理、对HTTPS的支持以及对HTTP/1.1和HTTP/2的兼容性。 4. **ksoap2-...

    android httpclient demo

    然而,由于Android API Level 23之后不再支持HttpClient,开发者现在更多地转向使用OkHttp或Retrofit等现代网络库。尽管如此,对于旧项目或者对HttpClient有特定需求的场景,理解其工作原理和用法仍然很有价值。 1....

    Android HttpClient源码

    另外,HttpClient支持重试策略和连接管理,通过`HttpRequestRetryHandler`和`ConnectionManager`可以定制网络失败后的处理方式和连接池的管理。 总的来说,理解Android HttpClient的源码能够帮助我们更好地掌握网络...

    Android HttpClient Network Lib

    HttpClient库为开发者提供了一种方便、灵活的方式来执行HTTP请求,获取服务器数据。本知识点将详细介绍如何在Android中使用HttpClient库进行网络操作,以及如何理解和使用提供的jar包和源码。 首先,让我们了解一下...

    HttpClient for android 4 3 5 jar

    总之,HttpClient 4.3.5是一个强大的HTTP客户端库,它提供了丰富的功能和良好的性能,尽管在新版本的Android中已不推荐使用,但对于支持旧版本Android的应用或者对性能有较高要求的项目,HttpClient仍然是一种可靠的...

    Android_HttpClient_jar包+HttpClientJarAndSource

    HttpClient的优势在于其强大的功能和良好的可扩展性,支持多种HTTP请求方式,可以方便地处理复杂请求。然而,随着Android版本的更新,HttpClient逐渐被更现代的HttpURLConnection取代,因为后者更轻量级、性能更好且...

    Android httpclient httpmine4j

    同时,由于系统级别的限制,不同Android版本可能需要不同的处理方式。例如,低于Android 9.0(API级别28)的设备可能需要处理SSL证书问题,高于这个版本的设备则可以使用AndroidX的HttpURLConnection替代HttpClient...

    android httpclient文件上传 http协议post get方法向服务器传输数据

    3. **HTTPClient文件上传**:在Android中,HTTPClient支持文件上传,这在处理用户上传图片、音频等文件的场景中非常常见。文件上传通常涉及MultipartEntityBuilder,它允许我们将文件作为多部分实体的一部分发送。...

    Android Asynchronous HTTPClient的实现和优化

    总之,Android Asynchronous HTTPClient是实现异步网络请求的一种有效工具,但在实际项目中,开发者应根据需求选择最合适的网络库,并结合各种优化策略,确保应用的性能和用户体验。随着技术的发展,不断学习和尝试...

    Android使用HttpClient上传文件到服务器完整实例

    但如果你的项目支持较低的Android版本,HttpClient仍然是一个可行的选择。 总结来说,Android通过HttpClient上传文件到服务器涉及以下几个关键步骤: 1. 添加HttpClient及相关库。 2. 创建HttpClient和HttpPost对象...

    AndroidHttpClient详解及调用示例

    总之,AndroidHttpClient为Android开发者提供了一种方便的方式来执行HTTP请求,虽然已被弃用,但在旧版本的Android系统中仍有一定的使用价值。不过,为了保持应用程序的兼容性和性能,建议采用更现代的HTTP客户端库...

    commons-httpclient包和ksoap2-android-assembly包

    在您提供的信息中,"commons-httpclient包"和"ksoap2-android-assembly包"正是两个关键的组件,它们分别处理HTTP通信和SOAP协议的解析。 **Apache Commons HttpClient** Apache Commons HttpClient是一个成熟的...

    Http(get)请求数据Android Studio使用HttpClient

    本教程将聚焦于使用`HttpClient`库进行GET请求,这是获取远程资源最常见的方式。请注意,本教程不涉及POST请求,POST主要用于向服务器提交数据。 ## 1. Android HttpClient介绍 `HttpClient`是Apache HTTP组件的一...

    httpclient-3.1

    4. 创建HTTP请求:HttpClient支持多种HTTP方法,通过`GetMethod`、`PostMethod`等类来创建请求。例如,发起一个GET请求: ```java GetMethod getMethod = new GetMethod("http://example.com"); ``` 5. 执行请求...

    android httpclient 访问服务器 获取json数据

    由于Android API 23及以上版本已不再支持Apache HTTPClient,因此可能需要手动添加依赖。在你的`build.gradle`文件的`dependencies`块中,添加如下代码: ```groovy implementation 'org.apache.httpcomponents:...

Global site tag (gtag.js) - Google Analytics