在 ktor HTTPClient 中解析错误主体
Parsing an error body in a ktor HTTPClient
我有一个 api returns 错误正文,在发送错误请求时包含正确的错误信息。例如,我得到状态代码 400 和以下正文 -
{
"errorCode": 1011,
"errorMessage": "Unable to get Child information"
}
现在,当我为此在多平台模块中编写 ktor 客户端时,我在响应验证器中捕获了它,例如 -
HttpResponseValidator {
validateResponse {
val statusCode = it.status.value
when (statusCode) {
in 300..399 -> print(it.content.toString())
in 400..499 -> {
print(it.content.toString())
throw ClientRequestException(it)
}
in 500..599 -> print(it.content.toString())
}
}
handleResponseException {
print(it.message)
}
}
我的问题是我无法访问 validateResponse
或 handleResponseException
中的响应错误正文。有没有一种方法可以捕获并解析它以获取服务器发送的实际错误?
您可以声明一个数据class错误来表示您期望的错误响应。
import kotlinx.serialization.Serializable
@Serializable
data class Error(
val errorCode: Int, //if by errorCode you mean the http status code is not really necessary to include here as you already know it from the validateResponse
val errorMessage: String
)
您可以享受暂停乐趣来解析响应并将其作为错误数据的实例 class
suspend fun getError(responseContent: ByteReadChannel): Error {
responseContent.readUTF8Line()?.let {
return Json(JsonConfiguration.Stable).parse(Error.serializer(), it)
}
throw IllegalArgumentException("not a parsable error")
}
然后在 handleResponseException 里面
handleResponseException { cause ->
val error = when (cause) {
is ClientRequestException -> exceptionHandler.getError(cause.response.content)
// other cases here
else -> // throw Exception() do whatever you need
}
//resume with the error
}
你可以根据抛出异常的错误实现一些逻辑,并在代码的其他地方捕获它
例如
when (error.errorCode) {
1-> throw MyCustomException(error.errorMessage)
else -> throw Exception(error.errorMessage)
}
希望对你有帮助
以防万一这有助于其他人在此 space 中进行搜索,在我的 ktor 服务设计中,response.readText
对我来说是有意义的:
try {
httpClient.post...
} catch(cre: ClientRequestException){
runBlocking {
val content = cre.response?.readText(Charset.defaultCharset())
val cfResponse = Gson().fromJson(content, CfResponse::class.java)
...
}
}
花了几个小时后,我通过以下步骤得到了错误正文。
1.为错误定义模型 class。就我而言,它类似于
@Serializable
data class MyException(
val message : String,
val code : String,
val type : String,
val status_code : Int
) : RuntimeException()
你可以看到我还将自定义 class 扩展到 RuntimeException,因为我希望我的 class 表现得像异常 class
2。调用 API
try {
val mClient = KtorClientFactory().build()
val res = mClient.post<MemberResponse>("${baseURL}user/login/") {
//.....
}
emit(DataState.Success(res))
} catch (ex: Exception) {
if (ex is ClientRequestException) {
val res = ex.response.readText(Charsets.UTF_8)
try {
val myException = Json { ignoreUnknownKeys = true }
.decodeFromString(MyException.serializer(), res)
emit(DataState.Error(myException))
} catch (ex: Exception) {
ex.printStackTrace()
}
} else
emit(DataState.Error(ex))
}
That's it. You've parsed the error body.
要简明扼要地理解它,只需要分两步进行。
1. val res = ex.response.readText(字符集.UTF_8)
2。 val myException = Json { ignoreUnknownKeys = true }.decodeFromString(MyException.serializer(), res)
正如其他人所指出的,您可以声明错误对象的数据 class,并且由于 Ktor 已经设置了序列化程序,我们可以从 ResponseException
获取响应主体。
为了方便使用,这里有一个扩展函数:
suspend inline fun <reified E> ResponseException.errorBody(): E? =
try {
response.body()
} catch (e: SerializationException) {
null
}
我有一个 api returns 错误正文,在发送错误请求时包含正确的错误信息。例如,我得到状态代码 400 和以下正文 -
{
"errorCode": 1011,
"errorMessage": "Unable to get Child information"
}
现在,当我为此在多平台模块中编写 ktor 客户端时,我在响应验证器中捕获了它,例如 -
HttpResponseValidator {
validateResponse {
val statusCode = it.status.value
when (statusCode) {
in 300..399 -> print(it.content.toString())
in 400..499 -> {
print(it.content.toString())
throw ClientRequestException(it)
}
in 500..599 -> print(it.content.toString())
}
}
handleResponseException {
print(it.message)
}
}
我的问题是我无法访问 validateResponse
或 handleResponseException
中的响应错误正文。有没有一种方法可以捕获并解析它以获取服务器发送的实际错误?
您可以声明一个数据class错误来表示您期望的错误响应。
import kotlinx.serialization.Serializable
@Serializable
data class Error(
val errorCode: Int, //if by errorCode you mean the http status code is not really necessary to include here as you already know it from the validateResponse
val errorMessage: String
)
您可以享受暂停乐趣来解析响应并将其作为错误数据的实例 class
suspend fun getError(responseContent: ByteReadChannel): Error {
responseContent.readUTF8Line()?.let {
return Json(JsonConfiguration.Stable).parse(Error.serializer(), it)
}
throw IllegalArgumentException("not a parsable error")
}
然后在 handleResponseException 里面
handleResponseException { cause ->
val error = when (cause) {
is ClientRequestException -> exceptionHandler.getError(cause.response.content)
// other cases here
else -> // throw Exception() do whatever you need
}
//resume with the error
}
你可以根据抛出异常的错误实现一些逻辑,并在代码的其他地方捕获它 例如
when (error.errorCode) {
1-> throw MyCustomException(error.errorMessage)
else -> throw Exception(error.errorMessage)
}
希望对你有帮助
以防万一这有助于其他人在此 space 中进行搜索,在我的 ktor 服务设计中,response.readText
对我来说是有意义的:
try { httpClient.post... } catch(cre: ClientRequestException){ runBlocking { val content = cre.response?.readText(Charset.defaultCharset()) val cfResponse = Gson().fromJson(content, CfResponse::class.java) ... } }
花了几个小时后,我通过以下步骤得到了错误正文。
1.为错误定义模型 class。就我而言,它类似于
@Serializable
data class MyException(
val message : String,
val code : String,
val type : String,
val status_code : Int
) : RuntimeException()
你可以看到我还将自定义 class 扩展到 RuntimeException,因为我希望我的 class 表现得像异常 class
2。调用 API
try {
val mClient = KtorClientFactory().build()
val res = mClient.post<MemberResponse>("${baseURL}user/login/") {
//.....
}
emit(DataState.Success(res))
} catch (ex: Exception) {
if (ex is ClientRequestException) {
val res = ex.response.readText(Charsets.UTF_8)
try {
val myException = Json { ignoreUnknownKeys = true }
.decodeFromString(MyException.serializer(), res)
emit(DataState.Error(myException))
} catch (ex: Exception) {
ex.printStackTrace()
}
} else
emit(DataState.Error(ex))
}
That's it. You've parsed the error body.
要简明扼要地理解它,只需要分两步进行。
1. val res = ex.response.readText(字符集.UTF_8)
2。 val myException = Json { ignoreUnknownKeys = true }.decodeFromString(MyException.serializer(), res)
正如其他人所指出的,您可以声明错误对象的数据 class,并且由于 Ktor 已经设置了序列化程序,我们可以从 ResponseException
获取响应主体。
为了方便使用,这里有一个扩展函数:
suspend inline fun <reified E> ResponseException.errorBody(): E? =
try {
response.body()
} catch (e: SerializationException) {
null
}