使用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
相关产品推荐
相关产品推荐

