Android 4.4 以下,OkHttp访问Https报错,设置了sslSocketFactory仍无效的解决方法
背景
Android 4.4 及以下,使用 OkHttp 发送 Https 请求,报以下错误:
javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x6b712c90: Failure in SSL library, usually a protocol errorerror:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x68111cd4:0x00000000)at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:448)at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:302)at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:270)at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:162)at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257)at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)at okhttp3.RealCall$AsyncCall.execute(RealCall.java:147)at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)at java.lang.Thread.run(Thread.java:841)Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x6b712c90: Failure in SSL library, usually a protocol errorerror:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x68111cd4:0x00000000)at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)... 23 more
一、确保OkHttp的Https配置正确
首先配制好 sslSocketFactory 和 hostnameVerifier:
import android.annotation.SuppressLint
import java.net.InetAddress
import java.net.Socket
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManagerclass MySSLSocketFactory(tm: TrustManager = TrustAllTrustManager()) : SSLSocketFactory() {var internalSSLSocketFactory: SSLSocketFactoryvar context: SSLContext = SSLContext.getInstance("TLSv1.1")init {context.init(null, arrayOf(tm), null)internalSSLSocketFactory = context.socketFactory}override fun getDefaultCipherSuites(): Array<String> {return internalSSLSocketFactory.defaultCipherSuites}override fun createSocket(s: Socket?, host: String?, port: Int, autoClose: Boolean): Socket {val sslSocket = context.socketFactory?.createSocket(s, host, port, autoClose) as SSLSocketsslSocket.enabledProtocols = arrayOf("TLSv1.2", "TLSv1.1")return sslSocket}override fun getSupportedCipherSuites(): Array<String> {return internalSSLSocketFactory.supportedCipherSuites}override fun createSocket(host: String?, port: Int): Socket {val sslSocket = context.socketFactory?.createSocket(host, port) as SSLSocketsslSocket.enabledProtocols = arrayOf("TLSv1.2", "TLSv1.1")return sslSocket}override fun createSocket(host: String?, port: Int, localHost: InetAddress?, localPort: Int): Socket {val sslSocket = context.socketFactory?.createSocket(host, port, localHost, localPort) as SSLSocketsslSocket.enabledProtocols = arrayOf("TLSv1.2", "TLSv1.1")return sslSocket}override fun createSocket(host: InetAddress?, port: Int): Socket {val sslSocket = context.socketFactory?.createSocket(host, port) as SSLSocketsslSocket.enabledProtocols = arrayOf("TLSv1.2", "TLSv1.1")return sslSocket}override fun createSocket(address: InetAddress?, port: Int, localAddress: InetAddress?, localPort: Int): Socket {val sslSocket = context.socketFactory?.createSocket(address, port, localAddress, localPort) as SSLSocketsslSocket.enabledProtocols = arrayOf("TLSv1.2", "TLSv1.1")return sslSocket}@SuppressLint("CustomX509TrustManager", "TrustAllX509TrustManager")class TrustAllTrustManager : X509TrustManager {@Throws(CertificateException::class)override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {}@Throws(CertificateException::class)override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {}override fun getAcceptedIssuers(): Array<X509Certificate> {return arrayOf()}}
}public class SSLSocketClient {//获取这个SSLSocketFactorypublic static SSLSocketFactory getSSLSocketFactory() {try {SSLContext sslContext = SSLContext.getInstance("SSL");sslContext.init(null, getTrustManager(), new SecureRandom());return sslContext.getSocketFactory();} catch (Exception e) {throw new RuntimeException(e);}}//获取TrustManagerprivate static TrustManager[] getTrustManager() {return new TrustManager[]{new X509TrustManager() {@Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType) {}@Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType) {}@Overridepublic X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];}}};}//获取HostnameVerifierpublic static HostnameVerifier getHostnameVerifier() {HostnameVerifier hostnameVerifier = new HostnameVerifier() {@Overridepublic boolean verify(String s, SSLSession sslSession) {return true;}};return hostnameVerifier;}
}
在OkHttp中使用:
val tm = TrustAllTrustManager()val client = OkHttpClient.Builder().sslSocketFactory(MySSLSocketFactory(tm), tm).hostnameVerifier(SSLSocketClient.getHostnameVerifier()).build()val request = Request.Builder().url(url).build()client.newCall(request).enqueue(object : Callback {override fun onFailure(call: Call, e: IOException) {Log.w(TAG, "onFailure: ", e)onResult(Log.getStackTraceString(e))}override fun onResponse(call: Call, response: Response) {val result = response.body()?.string()onResult(result)}})
二、仍然报错的解决方案
如果通过以上的配置,仍然报 Failure in SSL library, usually a protocol error 的错,则有以下两种解决方案:
1. 降级OkHttp
将 OkHttp 降级到 3.9.0,即可正常请求。
2. 配置ConnectionSpec
在 OkHttpClient 创建的过程中,添加 ConnectionSpec 的配置,如下:
// ConnectionSpec的配置val spec = ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS).tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0).cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA).build()val tm = TrustAllTrustManager()val client = OkHttpClient.Builder().connectionSpecs(Collections.singletonList(spec)).sslSocketFactory(MySSLSocketFactory(tm), tm).hostnameVerifier(SSLSocketClient.getHostnameVerifier()).build()val request = Request.Builder().url(url).build()client.newCall(request).enqueue(object : Callback {override fun onFailure(call: Call, e: IOException) {Log.w(TAG, "onFailure: ", e)onResult(Log.getStackTraceString(e))}override fun onResponse(call: Call, response: Response) {val result = response.body()?.string()onResult(result)}})
相关文章:
Android 4.4 以下,OkHttp访问Https报错,设置了sslSocketFactory仍无效的解决方法
背景 Android 4.4 及以下,使用 OkHttp 发送 Https 请求,报以下错误: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl0x6b712c90: Failure in SSL library, usually a protocol erro…...
如何扫码查看企业介绍及填写招聘表?招聘二维码在线生成的方法
现在很多企业会通过生成二维码的方式来做企业介绍以及企业招聘,企业信息通过图片、文字、视频及其他内容展示,再创建合适的表单让扫码者按照制定的内容来填写对应的信息,从而完成扫码招聘的目的。 对于也想采用这种方式的小伙伴,…...
如何限制一个账号只在一处登陆
大家好,我是广漂程序员DevinRock! 1. 需求分析 前阵子,和问答群里一个前端朋友,随便唠了唠。期间他问了我一个问题,让我印象深刻。 他问的是,限制同一账号只能在一处设备上登录,是如何实现的…...
日常工作总结
日常工作总结 1000. JAVA基础1. 泛型1.1 泛型和Object的区别 1100. Spring1. 常用注解1.1 ControllerAdvice注解1.2 缓存Cacheable 2. 常用方法2.1 BeanUtils.copyProperties的用法 3. 常用功能组件3.1 过滤器Filter 2000. Linux应用 1000. JAVA基础 1. 泛型 1.1 泛型和Objec…...
Android Activity启动模式
文章目录 Android Activity启动模式概述四种启动模式Intent标记二者区别 Android Activity启动模式 概述 Activity 的管理方式是任务栈。栈是先进后出的结构。 四种启动模式 启动模式说明适用场景standard标准模式默认模式,每次启动Activity都会创建一个新的Act…...
【JavaScript】面试手撕防抖
引入 防抖可是前端面试时最频繁考察的知识点了,首先,我们先了解防抖的概念是什么。咳咳。👀 防抖: 首先它是常见的性能优化技术,主要用于处理频繁触发的浏览器事件,如窗口大小变化、滚动事件、输入框内容…...
【Kubernetes】K3S
目录 前言一、原理单体架构高可用架构 二、初始化1.配置yum源2.关掉防火墙3.关掉selinux4. 修改内核参数5.关掉swap交换分区 三、安装master节点1. 安装container2.启动master服务 四、安装node节点五、卸载六、总结 前言 各位小伙伴们,大家好,小涛又来…...
Docker实战——容器
目录 Docker 容器的基本概念与操作1.使用“docker create”创建容器。这里基于Nginx的镜像创建了一个容器,名字为mycontainer。2.使用“docker ps -a”命令查看所有的容器,这时的容器不一定是运行状态。3.使用 “docker start” 命令可以启动容器。4.使用…...
亚信安慧AntDB开启超融合数据库新纪元
(一) 前言 据统计,在信息化时代的今天,人们一天所接触到的信息量,是古人一辈子所能接收到的信息量的总和。当今社会中除了信息量“多”以外,人们对信息处理的“效率”和“速度”的要求也越来越高。譬如&…...
数学建模【多元线性回归模型】
一、多元线性回归模型简介 回归分析是数据分析中最基础也是最重要的分析工具,绝大多数的数据分析问题,都可以使用回归的思想来解决。回归分析的任务就是,通过研究自变量X和因变量Y的相关关系,尝试去解释Y的形成机制,进…...
【 10X summary report】怎么看?详细解读笔记
报告内容 在开始正式的分析之前,需要查看在对齐和计数过程中生成的任何总结统计信息。下图是由Cell Ranger工具创建的10X总结报告,在从10X scRNA-seq实验生成计数矩阵时会生成。 The left half of the report describes sequencing and mapping statist…...
K8S—Pod控制器
目录 1.什么是POD控制器 2.POD控制器有几种类型 3.POD与控制器之间的关系 4.示例 4.1 Deployment 4.2 SatefulSet ①为什么要有headless? ②为什么要有volumeClainTemplate? ③服务发现:就是应用服务之间相互定位的过程。 ④K8S里服…...
LabVIEW石油钻机提升系统数字孪生技术
LabVIEW石油钻机提升系统数字孪生技术 随着数字化、信息化、智能化的发展,石油钻采过程中的石油钻机数字化技术提升成为了提高钻井效率、降低生产成本的重要途径。基于中石油云平台提供的数据,采用数字孪生技术,对石油钻机提升系统进行数字化…...
C#双向链表实现:在当前节点后插入新数据的方法Insert()
目录 1.定义一个泛型节点类并自动属性 2.定义链表类,并实现Append、Print、MoveFirst、 Insert 3.Main方法 1.定义一个泛型节点类并自动属性 /// <summary> /// 定义泛型节点类 /// </summary> /// <typeparam name"T">泛型运算符&…...
10-Java装饰器模式 ( Decorator Pattern )
Java装饰器模式 摘要实现范例 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构 装饰器模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供…...
Vue.js 实用技巧:深入理解 Vue.set 方法
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
单词规律00
题目链接 单词规律 题目描述 注意点 pattern只包含小写英文字母s只包含小写英文字母和 ’ ’s不包含任何前导或尾随对空格s中每个单词都被 单个空格 分隔 解答思路 本题与上一次同构字符串类似,思路可以参照同构字符串 代码 class Solution {public boolean …...
vue3 vite项目一运行就401(Unauthorized)
问题:项目一执行: pnpm run dev, 启动就出错, Failed to load resource: the server responded with a status of 401 (Unauthorized) 分析: 项目之前是正常运行的,没有问题,回溯刚刚改动,还原…...
LeetCode102.二叉树的层序遍历
题目 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 示例 输入:root [3,9,20,null,null,15,7] 输出:[[3],[9,20],[15,7]]输入:root [1] 输出&am…...
Java底层自学大纲_JVM篇
JVM专题_自学大纲所属类别学习主题建议课时(h) A 深入理解Java虚拟机001 JVM类加载器设计原理2.5 A 深入理解Java虚拟机002 基于SPI破解双亲委派机制2.5 A 深入理解Java虚拟机003 JVM内部结构分析2.5 A 深入理解Java虚拟机004 字符串常量池原理2.5 …...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...
