问题:
项目中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
相关推荐
2. **Httpmime**:这是Apache HttpClient的一个扩展,主要添加了对MIME类型的处理支持,包括文件上传。`httpmime-4.0.jar`包含了`MultipartEntity`类,这个类是实现文件上传的核心,允许我们构建一个包含多个部分的...
此外,由于Android系统的限制,从API Level 19开始,HttpClient默认不再支持SSL。如果需要与HTTPS服务器通信,需要自定义SSLSocketFactory。 总之,Android HttpClient提供了一套完整的HTTP通信框架,允许开发者...
Struts2、Android和HttpClient是三个关键的技术领域,它们在本次文件上传的场景中相互结合。Struts2是一个流行的Java Web框架,用于构建MVC(模型-视图-控制器)结构的应用程序。Android是Google开发的移动操作系统...
总之,Android中的HttpClient虽然在新版本中被弃用,但它仍然是一种有效的工具,尤其是在处理复杂的网络请求和代理设置时。通过理解HttpClient的配置、代理设置、请求发起、响应处理和异常管理,你可以有效地实现...
虽然面临被替代的命运,但在某些情况下,如对低版本Android的支持和需要高级功能时,它仍然是一种实用的选择。结合Android_HTTP服务实例.docx,可以更深入地了解如何在实际项目中应用这些概念。
3. **httpclient-4.5.6.jar**: 这是HttpClient的较新版本,相对于commons-httpclient,它有更多改进和优化,包括更好的性能、更完善的错误处理、对HTTPS的支持以及对HTTP/1.1和HTTP/2的兼容性。 4. **ksoap2-...
然而,由于Android API Level 23之后不再支持HttpClient,开发者现在更多地转向使用OkHttp或Retrofit等现代网络库。尽管如此,对于旧项目或者对HttpClient有特定需求的场景,理解其工作原理和用法仍然很有价值。 1....
另外,HttpClient支持重试策略和连接管理,通过`HttpRequestRetryHandler`和`ConnectionManager`可以定制网络失败后的处理方式和连接池的管理。 总的来说,理解Android HttpClient的源码能够帮助我们更好地掌握网络...
HttpClient库为开发者提供了一种方便、灵活的方式来执行HTTP请求,获取服务器数据。本知识点将详细介绍如何在Android中使用HttpClient库进行网络操作,以及如何理解和使用提供的jar包和源码。 首先,让我们了解一下...
总之,HttpClient 4.3.5是一个强大的HTTP客户端库,它提供了丰富的功能和良好的性能,尽管在新版本的Android中已不推荐使用,但对于支持旧版本Android的应用或者对性能有较高要求的项目,HttpClient仍然是一种可靠的...
HttpClient的优势在于其强大的功能和良好的可扩展性,支持多种HTTP请求方式,可以方便地处理复杂请求。然而,随着Android版本的更新,HttpClient逐渐被更现代的HttpURLConnection取代,因为后者更轻量级、性能更好且...
同时,由于系统级别的限制,不同Android版本可能需要不同的处理方式。例如,低于Android 9.0(API级别28)的设备可能需要处理SSL证书问题,高于这个版本的设备则可以使用AndroidX的HttpURLConnection替代HttpClient...
3. **HTTPClient文件上传**:在Android中,HTTPClient支持文件上传,这在处理用户上传图片、音频等文件的场景中非常常见。文件上传通常涉及MultipartEntityBuilder,它允许我们将文件作为多部分实体的一部分发送。...
总之,Android Asynchronous HTTPClient是实现异步网络请求的一种有效工具,但在实际项目中,开发者应根据需求选择最合适的网络库,并结合各种优化策略,确保应用的性能和用户体验。随着技术的发展,不断学习和尝试...
但如果你的项目支持较低的Android版本,HttpClient仍然是一个可行的选择。 总结来说,Android通过HttpClient上传文件到服务器涉及以下几个关键步骤: 1. 添加HttpClient及相关库。 2. 创建HttpClient和HttpPost对象...
总之,AndroidHttpClient为Android开发者提供了一种方便的方式来执行HTTP请求,虽然已被弃用,但在旧版本的Android系统中仍有一定的使用价值。不过,为了保持应用程序的兼容性和性能,建议采用更现代的HTTP客户端库...
在您提供的信息中,"commons-httpclient包"和"ksoap2-android-assembly包"正是两个关键的组件,它们分别处理HTTP通信和SOAP协议的解析。 **Apache Commons HttpClient** Apache Commons HttpClient是一个成熟的...
本教程将聚焦于使用`HttpClient`库进行GET请求,这是获取远程资源最常见的方式。请注意,本教程不涉及POST请求,POST主要用于向服务器提交数据。 ## 1. Android HttpClient介绍 `HttpClient`是Apache HTTP组件的一...
4. 创建HTTP请求:HttpClient支持多种HTTP方法,通过`GetMethod`、`PostMethod`等类来创建请求。例如,发起一个GET请求: ```java GetMethod getMethod = new GetMethod("http://example.com"); ``` 5. 执行请求...
由于Android API 23及以上版本已不再支持Apache HTTPClient,因此可能需要手动添加依赖。在你的`build.gradle`文件的`dependencies`块中,添加如下代码: ```groovy implementation 'org.apache.httpcomponents:...