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

使用ksoap2 Kotlin发起HTTPS SOAP请求遇500错误求助

Kotlin ksoap2调用HTTPS SOAP API 500错误解决方案

问题背景

使用Kotlin的ksoap2库调用HTTPS的SOAP API,持有带密码的.pfx证书,同时需要用户名密码认证。WcfStorm中配置证书、用户名密码及TLS后请求正常,但代码执行transport.call(soapAction, envelope, headerList)时返回500 HTTP状态码。

核心问题排查与修复方案

1. 修复自定义HTTPS传输类的SSLSocketFactory注入

当前CustomHttpsTransportSE仅继承了HttpsTransportSE,但未重写getSSLSocketFactory方法,导致ksoap2无法使用你配置的自定义SSL套接字工厂,证书验证逻辑不生效。

修改CustomHttpsTransportSE.kt:

class CustomHttpsTransportSE(
    host: String,
    port: Int,
    file: String,
    timeout: Int,
    private val sslSocketFactory: SSLSocketFactory
) : HttpsTransportSE(host, port, file, timeout) {
    // 重写方法返回自定义的SSLSocketFactory
    override fun getSSLSocketFactory(): SSLSocketFactory {
        return sslSocketFactory
    }
}

2. 调整用户名密码的传递方式(关键)

WcfStorm中配置的是安全级别用户名/密码认证,通常对应WS-Security协议,需将凭证放在SOAP头而非请求体参数中。你当前的代码将用户名密码作为SoapObject的属性传入请求体,这与WCF服务的预期不符,是500错误的常见原因。

修改步骤:

  • 移除请求体中的用户名密码属性:
    // 删掉这两行
    // request.addProperty("username", USERNAME)
    // request.addProperty("password", PASSWORD)
    
  • 添加WS-Security认证头:
    // 新增构建WS-Security头的函数
    private fun createWsseHeaders(username: String, password: String, soapAction: String): List<HeaderProperty> {
        val nonce = UUID.randomUUID().toString()
        val created = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).format(Date())
        // 计算密码摘要
        val passwordDigest = Base64.encodeToString(("$nonce$created$password").toByteArray(), Base64.NO_WRAP)
        val nonceBase64 = Base64.encodeToString(nonce.toByteArray(), Base64.NO_WRAP)
    
        val wsseXml = """
            <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                <wsse:UsernameToken>
                    <wsse:Username>$username</wsse:Username>
                    <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">$passwordDigest</wsse:Password>
                    <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">$nonceBase64</wsse:Nonce>
                    <wsse:Created>$created</wsse:Created>
                </wsse:UsernameToken>
            </wsse:Security>
        """.trimIndent()
    
        return listOf(
            HeaderProperty("SOAPAction", soapAction),
            HeaderProperty("Content-Type", "text/xml;charset=UTF-8"),
            HeaderProperty("Authorization", "WSSE profile=\"UsernameToken\""),
            HeaderProperty("X-WSSE", wsseXml)
        )
    }
    
  • 在主函数中替换headerList:
    val headerList = createWsseHeaders(username, password, soapAction)
    

3. 指定明确的TLS版本

部分服务器仅支持TLS 1.2或更高版本,泛用的TLS可能会协商到旧版本导致握手失败。修改SSLContext初始化代码:

val sslContext = SSLContext.getInstance("TLSv1.2").apply {
    init(keyManagerFactory.keyManagers, trustManagerFactory.trustManagers, null)
}

4. 开启调试对比请求差异

利用ksoap2的调试功能,打印实际发送的请求和服务器返回的响应,对比WcfStorm的请求内容,找出差异点。

修改catch块代码:

catch (e: Exception) {
    e.printStackTrace()
    // 打印请求和响应内容
    Log.d("SOAP_DEBUG", "Request:\n${transport.requestDump}")
    Log.d("SOAP_DEBUG", "Response:\n${transport.responseDump}")
    return emptyList()
}

5. 检查证书加载逻辑

确保.pfx证书文件放置在res/raw目录下,且密码完全匹配。可添加日志验证证书是否成功加载:

val keyStore = KeyStore.getInstance("PKCS12").apply {
    load(context.resources.openRawResource(R.raw.CERTIFIKAT), "SIFRA".toCharArray())
    // 验证证书条目
    Log.d("CERT_DEBUG", "Loaded certificate aliases: ${keyStore.aliases().toList()}")
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 20:33:12