You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Kotlin中使用Retrofit遇Handshake Failed错误,如何解决?

解决Retrofit发起HTTPS请求时的Handshake Failed错误

问题背景

使用Kotlin+Retrofit调用HTTPS接口时触发Handshake Failed错误,错误信息在onFailure回调中捕获。相关代码及接口信息如下:

MainActivity核心代码

fun getMyData(){
     val Base_URL="https://tgju.amirhossein.info/"
     val retrofitBuilder= Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(Base_URL)
            .build()
            .create(API::class.java)
     val retrofitData=retrofitBuilder.getData()
     retrofitData.enqueue(object: Callback<List<MyDataItem>?>{
         override fun onResponse(
             call: Call<List<MyDataItem>?>,
             response: Response<List<MyDataItem>?>
              ) {
                  val responseBody=response.body()!!
                  if (response.isSuccessful) {
                  val txt=findViewById<TextView>(R.id.txt)
                  txt.text= responseBody[0].key
                }
      }
      override fun onFailure(call: Call<List<MyDataItem>?>, t: Throwable) {
              val txt=findViewById<TextView>(R.id.txt)
              txt.text=t.message // 原代码t.Message为错误写法,Kotlin中应为t.message(小写m)
      }

  })
}

API接口定义

interface API { 
    @GET("api/price/currency") 
    fun getData(): Call<List<MyDataItem>>
}

数据实体类

data class MyDataItem( 
    val key: String, 
    val price: String, 
    val title: String 
)

服务器返回示例

[ 
    { "key": "price_dollar_rl", "price": "492,330", "title": "\u062f\u0644\u0627\u0631" }, 
    { "key": "price_eur", "price": "538,800", "title": "\u06cc\u0648\u0631\u0648" } 
]

接口地址

https://tgju.amirhossein.info/api/price/currency

解决方法

Handshake Failed本质是SSL/TLS握手验证失败,核心原因是服务器证书不被Android系统信任,以下是针对性解决方案:

1. 先修正代码错误

原代码中onFailure回调里的t.Message是语法错误,Kotlin中Throwable的错误信息属性为**t.message**(小写m),修正后才能正确显示完整错误详情,辅助排查问题。

2. 临时绕过SSL验证(仅测试环境使用)

如果是测试阶段需要快速验证接口功能,可配置Retrofit使用忽略SSL证书验证的OkHttpClient:

// 生成信任所有证书的OkHttpClient
private fun createUnsafeOkHttpClient(): OkHttpClient {
    try {
        val trustAllCerts = arrayOf<X509TrustManager>(object : X509TrustManager {
            override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {}
            override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {}
            override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
        })

        val sslContext = SSLContext.getInstance("SSL")
        sslContext.init(null, trustAllCerts, SecureRandom())
        val sslSocketFactory = sslContext.socketFactory

        return OkHttpClient.Builder()
            .sslSocketFactory(sslSocketFactory, trustAllCerts[0])
            .hostnameVerifier { _, _ -> true } // 忽略主机名匹配验证
            .build()
    } catch (e: Exception) {
        throw RuntimeException(e)
    }
}

修改Retrofit构建代码,添加自定义OkHttpClient:

val retrofitBuilder= Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create())
    .baseUrl(Base_URL)
    .client(createUnsafeOkHttpClient()) // 接入不安全的客户端
    .build()
    .create(API::class.java)

注意:此方法完全关闭SSL安全验证,严禁用于生产环境,会导致数据传输存在被劫持的风险。

3. 导入服务器证书到项目(生产环境推荐)

如果服务器使用自签名证书,正确做法是将证书导入项目,让App信任该证书:

  1. 将服务器的.cer格式证书放入项目res/raw目录(无raw目录则新建)。
  2. 编写代码生成信任该证书的OkHttpClient:
private fun createTrustedOkHttpClient(context: Context): OkHttpClient {
    try {
        val certificateFactory = CertificateFactory.getInstance("X.509")
        val inputStream = context.resources.openRawResource(R.raw.your_certificate) // 替换为你的证书文件名
        val certificate = certificateFactory.generateCertificate(inputStream)
        inputStream.close()

        val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
        keyStore.load(null, null)
        keyStore.setCertificateEntry("server", certificate)

        val tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm()
        val tmf = TrustManagerFactory.getInstance(tmfAlgorithm)
        tmf.init(keyStore)

        val sslContext = SSLContext.getInstance("TLS")
        sslContext.init(null, tmf.trustManagers, SecureRandom())

        return OkHttpClient.Builder()
            .sslSocketFactory(sslContext.socketFactory, tmf.trustManagers[0] as X509TrustManager)
            .build()
    } catch (e: Exception) {
        throw RuntimeException(e)
    }
}
  1. 在Retrofit构建时接入该客户端:
val retrofitBuilder= Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create())
    .baseUrl(Base_URL)
    .client(createTrustedOkHttpClient(this)) // 传入当前Context
    .build()
    .create(API::class.java)

4. 检查基础配置

  • 确保AndroidManifest.xml中添加了网络权限:
<uses-permission android:name="android.permission.INTERNET" />
  • 通过浏览器访问接口地址,确认服务器SSL证书未过期、域名与证书匹配。

内容的提问来源于stack exchange,提问作者Hos 8990

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 13:07:54