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

OkHttp转Ktor请求出现Chain validation failed错误求助

问题:OkHttp转Ktor实现后出现Chain validation failed错误

原OkHttp实现代码

val client = OkHttpClient()

val mediaType = MediaType.parse("application/x-www-form-urlencoded")
val body = RequestBody.create(mediaType, "tenant_id=xxxx&client_id=xxxx&client_secret=xxxx&resource=xxxx&grant_type=client_credentials")
val request = Request.Builder()
  .url("https://sxxx.com/axxx/oauth2/token")
  .post(body)
  .addHeader("Content-Type", "application/x-www-form-urlencoded")
  .build()

val response = client.newCall(request).execute()

我的Ktor实现代码

class Greeting {
        private val httpClient = HttpClient {
        }

        @Throws(Exception::class)
        suspend fun greeting(): String {
        val response = httpClient.request {
            method = HttpMethod.Post
            url {
                protocol = URLProtocol.HTTPS
                host = "sxxx.com"
                path("axxx/oauth2/token")
             //   encodedParameters
                trailingQuery = true
                parameters.append("tenant_id", "xxxx")
                parameters.append("client_id", "xxxx")
                parameters.append("client_secret", "xxxx")
                parameters.append("resource", "xxxx")
                parameters.append("grant_type", "client_credentials")
            }
            headers {
                append(HttpHeaders.ContentType, "application/x-www-form-urlencoded")
            }
        }
        return response.bodyAsText()
     }
}

调用Ktor代码的方式

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApplicationTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    val scope = rememberCoroutineScope()
                    var text by remember {
                        mutableStateOf("Loading")
                    }
                    LaunchedEffect(true){
                        scope.launch {
                            text = try {
                                Greeting().greeting()
                            } catch (e: Exception) {
                                e.localizedMessage ?: "error"
                            }
                        }
                    }
                    Greeting(text)
                }
            }
        }
    }
}

@Composable
fun Greeting(text: String) {
    Text(text = text)
}

遇到的问题

未获取到预期令牌,返回错误:Chain validation failed
错误截图


解决方案

1. 修正请求格式错误

原OkHttp是将表单参数放在POST请求体中,但你的Ktor代码错误地将参数放到了URL的Query部分,这会导致服务器无法识别参数。正确写法应该把参数放入请求体:

class Greeting {
    private val httpClient = HttpClient(Android) {
        // 后续添加SSL配置
    }

    @Throws(Exception::class)
    suspend fun greeting(): String {
        val response = httpClient.request {
            method = HttpMethod.Post
            url("https://sxxx.com/axxx/oauth2/token")
            // 指定表单内容类型
            contentType(ContentType.Application.FormUrlEncoded)
            // 将参数放入请求体
            setBody(FormDataContent(Parameters.build {
                append("tenant_id", "xxxx")
                append("client_id", "xxxx")
                append("client_secret", "xxxx")
                append("resource", "xxxx")
                append("grant_type", "client_credentials")
            }))
        }
        return response.bodyAsText()
    }
}

2. 解决SSL证书验证失败问题

Chain validation failed是SSL证书信任问题,分两种场景处理:

场景一:测试环境(自签名证书)

临时禁用证书验证(生产环境绝对禁止使用):

private val httpClient = HttpClient(Android) {
    engine {
        sslManager = SSLManager {
            trustManager = 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> = emptyArray()
            }
        }
    }
}

场景二:生产环境(正规CA证书)

如果服务器证书是正规CA签发,但系统未信任,可将证书导入项目并配置信任:

  1. 将证书文件(如server_cert.pem)放入src/main/res/raw目录
  2. 配置HttpClient:
private val httpClient = HttpClient(Android) {
    engine {
        sslManager = SSLManager {
            val certInputStream = context.resources.openRawResource(R.raw.server_cert)
            val certFactory = CertificateFactory.getInstance("X.509")
            val certificate = certFactory.generateCertificate(certInputStream) as X509Certificate
            
            val keyStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
                load(null)
                setCertificateEntry("server_cert", certificate)
            }
            
            val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply {
                init(keyStore)
            }
            trustManager = trustManagerFactory.trustManagers.first() as X509TrustManager
        }
    }
}

内容的提问来源于stack exchange,提问作者Hasan A Yousef

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 07:50:25