【问题标题】:SSL handshake aborted: ssl=0x74d2dc46c8: Failure in SSL library, usually a protocol error OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURESSL 握手中止:ssl=0x74d2dc46c8:SSL 库失败,通常是协议错误 OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE
【发布时间】:2020-03-29 20:08:23
【问题描述】:

在改造中,我在请求中发送 XML,作为响应,服务器将发送 XML 作为响应。我正在使用代理来使用该 API。但我总是得到 - HTTP FAILED: java.io.IOException: unexpected end of stream on null。我已经尝试过 stackoverflow 中提到的解决方案,但没有任何效果。下面的代码用于改造客户 -

    fun getRetrofitClient(context: Context): RestAPI {

    if (mRetrofitClient == null) {

        val cf: CertificateFactory = CertificateFactory.getInstance("X.509")
        val cert: InputStream = context.getResources().openRawResource(R.raw.mycert)
        val ca: Certificate
        ca = try {
            cf.generateCertificate(cert)
        } finally {
            cert.close()
        }

         val keyStoreType: String = KeyStore.getDefaultType()
        val keyStore: KeyStore = KeyStore.getInstance(keyStoreType)
        keyStore.load(null, null)
        keyStore.setCertificateEntry("ca", ca)
        val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("xxxx.xx.xx.xx",xxxx ))
        val tmfAlgorithm: String = TrustManagerFactory.getDefaultAlgorithm()
        val tmf: TrustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm)
        tmf.init(keyStore)

        val sslContext: SSLContext = SSLContext.getInstance("TLSv1.2")
        sslContext.init(null, tmf.getTrustManagers(), null)

        val spec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
            .tlsVersions(TlsVersion.TLS_1_2)
            .cipherSuites(
                CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
            CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA
            )
            .build()


        val httpClient = OkHttpClient.Builder()
            .followRedirects(true)
        .followSslRedirects(true)
        .connectTimeout(10, TimeUnit.MINUTES)
        .readTimeout(10, TimeUnit.MINUTES)
        .writeTimeout(10, TimeUnit.MINUTES)
        .sslSocketFactory(socketFactory)
        .socketFactory(socketFactory)
        .hostnameVerifier(getHostnameVerifier())
        .retryOnConnectionFailure(true)
        .proxy(proxy)
        .connectionSpecs(Collections.singletonList(spec))



        val retrofit = Retrofit.Builder()
            .baseUrl("https://xxx.xx.xx.xx:xxxx/xx/")
            .addConverterFactory(SimpleXmlConverterFactory.create())
            .client(httpClient.build())
            .build()
        mRetrofitClient = retrofit.create(RestAPI::class.java!!)
    }
    return mRetrofitClient!!
}

fun getHostnameVerifier(): HostnameVerifier? {
    return object : HostnameVerifier {
        override fun verify(hostname: String?, session: SSLSession?): Boolean {
            return true
        }
    }
}

以下代码用于 Rest API -

interface RestAPI {
    @Headers("Content-Type: text/xml","Connection: keep-alive","Transfer-Encoding: chunked","Cache-Control: no-cache","Accept: */*","Host: xxx.xx.xx.xx:xxxx","Accept-Encoding: gzip, deflate, br")
    @POST("BillQuery/V1.0")
    abstract fun billQuery(@Body input:String): Call<String>
}

我也试过 volley,同样的问题。但它在 Postman 中运行良好。我添加了像邮递员这样的标题。还是不行。

请帮忙。

【问题讨论】:

  • 没有代理也能用吗?
  • 如果没有代理,我无法从我的国家/地区访问该 API。

标签: android retrofit retrofit2 okhttp


【解决方案1】:

unexpected end of stream 可以在 Response-Headers 无法解析或 Response-Header Content-Length 中的长度与响应正文的实际长度不匹配时由 okhttp 抛出(参见 HTTP FAILED: java.io.IOException: unexpected end of stream exception while making https request)。

在您的情况下,okhttp 想要向 HTTP 代理发送未加密的连接,并且在此步骤中无法解析来自代理响应的响应标头,我猜。代理给 okhttp 一个无效的答案。可以试试 postman 通过 HTTP 连接代理吗?

【讨论】:

  • java.io.EOFException: \n not found: limit=0 content=...
  • 代理的响应是否包含任何标头?此错误表明代理没有返回任何标头。
  • 代理没有返回标头。
  • 这就是问题所在。 OkHttp 失败,因为预计代理会返回一些标头。
猜你喜欢
  • 2018-09-05
  • 2018-07-10
  • 2021-06-14
  • 2015-07-07
  • 2018-10-03
  • 2017-01-09
  • 2012-01-31
  • 1970-01-01
  • 2014-01-14
相关资源
最近更新 更多