【发布时间】:2021-12-16 09:11:22
【问题描述】:
我有一个 KMM 项目,我一直在其中使用 Ktor 进行 API 调用。我有一个要求,如果它们已过期,我需要在刷新令牌的帮助下更新我的访问令牌。基本上我只需要在我的 Ktor 客户端中添加一个身份验证模块。不,我已经检查了所有 Ktor documentation 并在我的 KMM 中添加了 Auth 模块。
现在,当我在我的 http 客户端中添加身份验证模块时,它会成功添加,并且每当我从任何 API 收到 UnAuthorized 用户错误时,它都会调用我的刷新令牌 API。问题是即使它调用了我的刷新令牌 API,但在刷新令牌成功时,它不会调用我从中收到 UnAuthorized 用户错误的其他 API。
它在 Android 中按预期工作,但唯一的问题是在 iOS 客户端中。
预期(在 Android Http 客户端中运行良好):-
- 调用任何 API -> 如果收到任何
UnAuthorized用户错误调用刷新令牌 API -> onSuccess of refresh token API -> 使用更新的刷新令牌再次调用第一个 API。
我面临的问题:-
- 调用任何 API -> 如果收到任何
UnAuthorized用户错误,则调用刷新令牌 API -> onSuccess of refresh token API -> 此步骤不执行任何操作,只会从第一个 API 引发未经授权的用户错误。
HttpClient 适用于 iOS:-
actual class HttpBaseClient {
actual val tokenClient = HttpClient {
defaultRequest {
host = ApiEndPoints.Base.url
url {
protocol = URLProtocol.HTTPS
}
contentType(ContentType.Application.Json)
header(CONNECTION, CLOSE)
}
install(JsonFeature) {
val json = kotlinx.serialization.json.Json {
ignoreUnknownKeys = true
coerceInputValues = true
}
serializer = KotlinxSerializer(json)
}
}
actual val httpClient: HttpClient = HttpClient {
defaultRequest {
host = ApiEndPoints.Base.url
url {
protocol = URLProtocol.HTTPS
}
contentType(ContentType.Application.Json)
header(CONNECTION, CLOSE)
}
// Validate Response
expectSuccess = false
// Install Auth
install(Auth) {
lateinit var refreshTokenInfo : LoginResponse
bearer {
refreshTokens { unauthorizedResponse: HttpResponse ->
NSLog("Unauthorized response received")
BaseAPIClass().refreshAuthToken().fold(
failed = {
// On Failed
NSLog("Token Failed"). // No Callback received here
},
succeeded = { response ->
refreshTokenInfo = response
NSLog("Token Updated") // No Callback received here even when API is success
}
)
BearerTokens(
accessToken = refreshTokenInfo.accessToken ?: "",
refreshToken = refreshTokenInfo.refreshToken ?: ""
)
}
}
}
// JSON Deserializer
install(JsonFeature) {
val json = kotlinx.serialization.json.Json {
ignoreUnknownKeys = true
coerceInputValues = true
}
serializer = KotlinxSerializer(json)
}
Android 客户端(几乎相同):-
actual class HttpBaseClient {
actual val tokenClient = HttpClient {
defaultRequest {
host = ApiEndPoints.Base.url
url {
protocol = URLProtocol.HTTPS
}
contentType(ContentType.Application.Json)
header(CONNECTION, CLOSE)
}
install(JsonFeature) {
val json = kotlinx.serialization.json.Json {
ignoreUnknownKeys = true
coerceInputValues = true
}
serializer = KotlinxSerializer(json)
}
install(Logging) {
logger = Logger.DEFAULT
level = LogLevel.ALL
}
}
actual val httpClient: HttpClient = HttpClient {
defaultRequest {
host = ApiEndPoints.Base.url
url {
protocol = URLProtocol.HTTPS
}
contentType(ContentType.Application.Json)
header(CONNECTION, CLOSE)
}
// Validate Response
expectSuccess = false
//Authentication
install(Auth) {
lateinit var refreshTokenInfo : LoginResponse
bearer {
refreshTokens { unauthorizedResponse: HttpResponse ->
BaseAPIClass().refreshAuthToken().fold(
failed = {
// On Failed
},
succeeded = { response ->
refreshTokenInfo = response
}
)
BearerTokens(
accessToken = refreshTokenInfo.accessToken ?: "",
refreshToken = refreshTokenInfo.refreshToken ?: ""
)
}
}
}
Ktor 版本:- 1.6.2(在阅读 this issue 后也尝试了 1.6.4,但没有用)
【问题讨论】:
-
我不知道如何解决你的问题,但首先你不需要为每个平台创建实现
HttpBaseClient。您可以将代码从这些类之一移动到公共模块中,它应该可以正常工作。重复代码可能会导致很多问题,KMM 旨在尽可能减少重复。 -
@PhilipDukhov 我知道我可以为这两个平台拥有一个客户端,但由于某种原因,我创建的两个平台都不同。无论如何,我已经为这两个平台创建了一个客户端,但对我来说仍然没有任何区别。它适用于 android,但不适用于 iOS。
标签: ios kotlin-multiplatform ktor kmm ktor-client