我们在更换服务器或者转为https的时候,在进行请求时产生异常

javax.net.ssl.SSLPeerUnverifiedException: No peer certificateW/System.err:     at com.android.org.conscrypt.SSLNullSession.getPeerCertificates(SSLNullSession.java:104)W/System.err:     at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:98)W/System.err:     at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:393)W/System.err:     at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:189)W/System.err:     at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:169)W/System.err:     at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:124)W/System.err:     at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:365)W/System.err:     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:608)W/System.err:     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:522)W/System.err:     at net.tsz.afinal.http.HttpHandler.makeRequestWithRetries(HttpHandler.java:79)W/System.err:     at net.tsz.afinal.http.HttpHandler.doInBackground(HttpHandler.java:115)W/System.err:     at net.tsz.afinal.core.AsyncTask$2.call(AsyncTask.java:145)W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)W/System.err:     at java.lang.Thread.run(Thread.java:818)

这个时候查了好几次,找不到原因,好蛋疼。。。。
后来上谷歌官网查询
产生原因一:

Protocol    Supported (API Levels)  Enabled by default (API Levels)
SSLv3               1+              1+
TLSv1           1+              1+
TLSv1.1         16+                 20+
TLSv1.2         16+                 20+

在不同的Android版本中,对应的TLS 版本不同,这时候,需要我们去让后台查询服务器,看是否支持,如果支持,在查看本地代码。

解决方法 一:

public class SSL extends SSLSocketFactory {private SSLSocketFactory defaultFactory;// Android 5.0+ (API level21) provides reasonable default settings// but it still allows SSLv3// https://developer.android.com/about/versions/android-5.0-changes.html#sslstatic String protocols[] = null, cipherSuites[] = null;static {try {SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();if (socket != null) {/* set reasonable protocol versions */// - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0)// - remove all SSL versions (especially SSLv3) because they‘re insecure nowList<String> protocols = new LinkedList<>();for (String protocol : socket.getSupportedProtocols())if (!protocol.toUpperCase().contains("SSL"))protocols.add(protocol);SSL.protocols = protocols.toArray(new String[protocols.size()]);/* set up reasonable cipher suites */if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {// choose known secure cipher suitesList<String> allowedCiphers = Arrays.asList(// TLS 1.2"TLS_RSA_WITH_AES_256_GCM_SHA384","TLS_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256","TLS_ECHDE_RSA_WITH_AES_128_GCM_SHA256",// maximum interoperability"TLS_RSA_WITH_3DES_EDE_CBC_SHA","TLS_RSA_WITH_AES_128_CBC_SHA",// additionally"TLS_RSA_WITH_AES_256_CBC_SHA","TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA","TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");List<String> availableCiphers = Arrays.asList(socket.getSupportedCipherSuites());// take all allowed ciphers that are available and put them into preferredCiphersHashSet<String> preferredCiphers = new HashSet<>(allowedCiphers);preferredCiphers.retainAll(availableCiphers);/* For maximum security, preferredCiphers should *replace* enabled ciphers (thus disabling* ciphers which are enabled by default, but have become unsecure), but I guess for* the security level of DAVdroid and maximum compatibility, disabling of insecure* ciphers should be a server-side task */// add preferred ciphers to enabled ciphersHashSet<String> enabledCiphers = preferredCiphers;enabledCiphers.addAll(new HashSet<>(Arrays.asList(socket.getEnabledCipherSuites())));SSL.cipherSuites = enabledCiphers.toArray(new String[enabledCiphers.size()]);}}} catch (IOException e) {throw new RuntimeException(e);}}public SSL(X509TrustManager tm) {try {SSLContext sslContext = SSLContext.getInstance("TLS");sslContext.init(null, (tm != null) ? new X509TrustManager[]{tm} : null, null);defaultFactory = sslContext.getSocketFactory();} catch (GeneralSecurityException e) {throw new AssertionError(); // The system has no TLS. Just give up.}}private void upgradeTLS(SSLSocket ssl) {// Android 5.0+ (API level21) provides reasonable default settings// but it still allows SSLv3// https://developer.android.com/about/versions/android-5.0-changes.html#sslif (protocols != null) {ssl.setEnabledProtocols(protocols);}if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && cipherSuites != null) {ssl.setEnabledCipherSuites(cipherSuites);}}@Override public String[] getDefaultCipherSuites() {return cipherSuites;}@Override public String[] getSupportedCipherSuites() {return cipherSuites;}@Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {Socket ssl = defaultFactory.createSocket(s, host, port, autoClose);if (ssl instanceof SSLSocket)upgradeTLS((SSLSocket) ssl);return ssl;}@Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException {Socket ssl = defaultFactory.createSocket(host, port);if (ssl instanceof SSLSocket)upgradeTLS((SSLSocket) ssl);return ssl;}@Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {Socket ssl = defaultFactory.createSocket(host, port, localHost, localPort);if (ssl instanceof SSLSocket)upgradeTLS((SSLSocket) ssl);return ssl;}@Override public Socket createSocket(InetAddress host, int port) throws IOException {Socket ssl = defaultFactory.createSocket(host, port);if (ssl instanceof SSLSocket)upgradeTLS((SSLSocket) ssl);return ssl;}@Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {Socket ssl = defaultFactory.createSocket(address, port, localAddress, localPort);if (ssl instanceof SSLSocket)upgradeTLS((SSLSocket) ssl);return ssl;}
}然后我们只需要给我们的请求设置这个SSLSocketFactory就可以了,我们以okhttp为例,如下://定义一个信任所有证书的TrustManager
final X509TrustManager trustAllCert = new X509TrustManager() {@Overridepublic void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {}@Overridepublic void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {}@Overridepublic java.security.cert.X509Certificate[] getAcceptedIssuers() {return new java.security.cert.X509Certificate[]{};}
};
//设置OkHttpClient
OkHttpClient client = new OkHttpClient.Builder().sslSocketFactory(new SSL(trustAllCert), trustAllCert).build();

产生原因二:
从异常信息中,我们可以看出网络请求过程中的握手过程中,握手被中断了

TCP建立连接时需要三次握手,在释放连接需要四次挥手;例如三次握手的过程如下:

第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;

第二次握手:服务器收到syn包,并会确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

可以看到握手时会在客户端和服务器之间传递一些TCP头信息,比如ACK标志、SYN标志以及挥手时的FIN标志等。

除了以上这些常见的标志头信息,还有另外一些标志头信息,比如推标志PSH、复位标志RST等。其中复位标志RST的作用就是“复位相应的TCP连接”。

另一个可能导致的“Connection reset”的原因是服务器设置了Socket.setLinger (true, 0)。但我检查过线上的tomcat配置,是没有使用该设置的,而且线上的服务器都使用了nginx进行反向代理,所以并不是该原因导致的。关于该原因上面的oracle文档也谈到了并给出了解释。

此外啰嗦一下,另外还有一种比较常见的错误“Connection reset by peer”,该错误和“Connection reset”是有区别的:

服务器返回了“RST”时,如果此时客户端正在从Socket套接字的输出流中读数据则会提示Connection reset”;

服务器返回了“RST”时,如果此时客户端正在往Socket套接字的输入流中写数据则会提示“Connection reset by peer”。

首先是出错了重试:这种方案可以简单防止“Connection reset”错误,然后如果服务不是“幂等”的则不能使用该方法;比如提交订单操作就不是幂等的,如果使用重试则可能造成重复提单。

然后是客户端和服务器统一使用TCP长连接:客户端使用TCP长连接很容易配置(直接设置HttpClient就好),而服务器配置长连接就比较麻烦了,就拿tomcat来说,需要设置tomcat的maxKeepAliveRequests、connectionTimeout等参数。另外如果使用了nginx进行反向代理或负载均衡,此时也需要配置nginx以支持长连接(nginx默认是对客户端使用长连接,对服务器使用短连接)。

使用长连接可以避免每次建立TCP连接的三次握手而节约一定的时间,但是我这边由于是内网,客户端和服务器的3次握手很快,大约只需1ms。ping一下大约0.93ms(一次往返);三次握手也是一次往返(第三次握手不用返回)。根据80/20原理,1ms可以忽略不计;又考虑到长连接的扩展性不如短连接好、修改nginx和tomcat的配置代价很大(所有后台服务都需要修改);所以这里并没有使用长连接。ping服务器的时间如下图:

最后的解决方案是客户端和服务器统一使用TCP短连接:我这边正是这么干的,而使用短连接既不用改nginx配置,也不用改tomcat配置,只需在使用HttpClient时使用http1.0协议并增加http请求的header信息(Connection: Close),源码如下:

httpGet.setProtocolVersion(HttpVersion.HTTP_1_0);
httpGet.addHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);

原因三:

理解这个问题,我试图找到连接背后的原因复位和我想出了以下原因:

在远程主机上的对等应用程序突然停止,重新启动主机,主机或远程网络接口被禁用,或远程主机使用硬关闭。
也可能导致这个错误,如果一个连接被打破,由于保持活动检测到故障,而一个或多个操作正在进行中。此时,正在进行的操作失败和后续操作将失败。Network dropped connection on reset(On Windows(WSAENETRESET))Connection reset by peer(On Windows(WSAECONNRESET))
如果目标服务器是由防火墙,这是真正在大多数情况下的保护,生存时间(TTL)或与该端口相关联的超时强行关闭空闲在给定的超时连接。这是我们关心的事
解析度:

在服务器端的事件,如突然停止服务,重新启动,禁用网络接口不能以任何方式处理。
在服务器端,配置防火墙与较高的生存时间(TTL)或超时值,如3600秒的指定端口。
客户可以“尝试”保持网络活跃,以避免或减少Connection reset by peer。
一般情况下要去的网络流量保持连接活着,问题/异常没有经常看到。的WiFi有至少机会Connection reset by peer。
与所述移动网络的2G,3G和4G,其中该分组数据传送是间歇的和依赖于移动网络的可用性,它可能无法重置在服务器侧和结果到的TTL计时器Connection reset by peer。
下面是项建议对各种论坛设置来解决问题

ConnectionTimeout:只有在建立连接超时使用。如果主机需要时间来连接这更高的价值,使客户端等待连接。
SoTimeout:插座超时它说在其内的数据分组被接收到考虑将该连接视为active.If没有在规定时间内接收到的数据的最大时间,连接被假定为停滞/断。
Linger:多达什么时候插座不应该当数据正在排队等待发送,并且关闭套接字函数被调用的插座上关闭。
TcpNoDelay:是否要禁用保存和积累的TCP数据包缓冲区,并送他们一旦达到阈值?设置为true,将跳过TCP缓冲,使每个请求立即发送。在网络中可以变慢通过增加由于更小和更频繁的分组传输的网络流量而引起的。
所以没有上述参数有助于保持网络活着,因而是无效的。

我发现一个设置,可以帮助解决这是这个函数的问题

setKeepAlive(true)
setSoKeepalive(HttpParams params, enableKeepalive=”true”)
我怎么解决我的问题?

设置 HttpConnectionParams.setSoKeepAlive(params, true)
抓住SSLException和检查的异常消息Connection reset by peer
如果发现异常,存储下载/阅读进度,并创建一个新的连接。
如果可能的话继续下载/阅读否则重新启动下载

网络请求No peer certificate相关推荐

  1. 老牛知点所以然-两种安卓两种网络请求框架(ksoap2-android okhttp)配置https

    什么是HTTPS 关于https与http的区别,耳朵都快被磨出茧子了,但是除了知道这玩意比http更安全之外,SSL握手阶段,到底发生了什么,也说不出一个具体的所以然来.囫囵了几篇关于安卓客户端不同 ...

  2. Swift - 使用SwiftHTTP通过HTTPS进行网络请求,及证书的使用

    (本文代码已升级至Swift3) 一,证书的生成,以及服务器配置 参考我前面写的这篇文章:Tomcat服务器配置https双向认证(使用keytool生成证书) 文章详细介绍了HTTPS,SSL/TL ...

  3. Swift - 使用Alamofire通过HTTPS进行网络请求,及证书的使用

    (本文代码已升级至Swift3) 我原来写过一篇文章介绍如何使用证书通过SSL/TLS方式进行网络请求(Swift - 使用URLSession通过HTTPS进行网络请求,及证书的使用),当时用的是 ...

  4. Python网络请求库Requests,妈妈再也不会担心我的网络请求了(二)

    本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 极客导航 即可关注,每个工作日都有文章更新. 一.概况 接着上篇说,如果你真以为Requests网络请求库只有Get请求和Post请求 ...

  5. 深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求(上)

    2019独角兽企业重金招聘Python工程师标准>>> 深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求 一.引言 本篇博客主要讨论如何在客户端与服务端之间进行HTTPS ...

  6. Charles 抓包夜神模拟器,实现对App网络请求的监控

    移动端的开发相对于Web开发,有一个很大的缺陷就是看不到网络请求.Web端开发,可以在控制台轻松看到所有的网络请求,测试人员能轻松看出来接口是否有问题.但是移动端就比较麻烦,需要代理网络请求进行抓包, ...

  7. 如何使用 Fiddler Everywhere 抓包手机模拟器上的网络请求

    手机模拟器上虽然有网络请求, 但是默认并不会走 Fiddler 代理 首先我们设置 Fiddler 允许其他机器连接到 Fiddler, 并且记录下该监听端口 8866 在本机上 cmd 执行 ipc ...

  8. xUtils3.x的网络请求封装和请求https之单向SSL验证

    很久没写博客了, 自己定的路已经走歪,菜鸟的进阶之路上我只是走了一步,自从发了一篇博客之后在没有来过这里,已经有一年了吧,今天再次回到这里. 言归正传,今天要写的是xUtils3.x网络请求的封装和请 ...

  9. HTTP HTTPS 及网络请求与响应

    HTTP URI的全称为 Uniform Resource Identifier,即统一资源标志符 URL的全称为 Universal Resource Locator,即统一资源定位符 URL是UR ...

最新文章

  1. akaze特征匹配怎么去掉不合适的点_SIFT特征点
  2. 先来先服务调度算法(FCFS)
  3. 软件著作权登记证书申请攻略
  4. LeetCode上读不懂题!看不懂测试用例的那些题(有生之年更新。。。)
  5. python程序在线更新_Python自动更新功能
  6. mysql havequerycache_如何开启MySQL的中的Query Cache缓存
  7. CodeForces 173B Chamber of Secrets(最短路)
  8. 2021-CSP-J2/S2 自我题解
  9. 模拟电路仿真LTspice(2):三极管特性曲线
  10. 异方差检验 python_stata教程03-异方差的检验和处理
  11. ARP报文头部格式和请求流程
  12. mysql help_深入理解mysql帮助命令(help)
  13. 1+X计算机视觉考证一些知识点
  14. python函数的四种参数传递方式
  15. xgboost, lightgbm, catboost, 谁才是预言之战的最终赢家?
  16. Spark数据倾斜解决方案(收藏级)
  17. PTE学术英语考试受全球广泛认可,2018中国考量快速增长
  18. 前端面试题(react)
  19. 金蝶云星空与旺店通集成解决方案(金蝶主管库存)
  20. R产生指定协方差阵的正态随机向量

热门文章

  1. 电商宝SCRM | 微信个人号的高效维护与变现
  2. 安卓使用小技巧 (转)
  3. 深度学习之神经网络的优化器篇
  4. html基础背景、边框样式、内外边框、盒子尺寸大小计算
  5. 《薄冰实用英语语法详解》连载之六:被动语态
  6. 《薄冰实用英语语法详解》连载之五:动词的时态
  7. 《薄冰实用英语语法详解》连载之七:助动词
  8. X-Plane飞行模拟资源整理一
  9. 【机器学习】建议收藏的 725 个机器学习术语表,太全了!
  10. 【计算机图形学】图形变换(以任意直线为对称轴的对称变换)