4

我有一个 api,它在发送错误请求时返回带有正确错误信息的错误正文。例如,我得到状态码 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。有没有办法我可以捕获并解析它以获取服务器发送的实际错误?

4

3 回答 3

9

您可以声明一个数据类 Error 来表示您期望的错误响应。

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
)

您可以享受暂停的乐趣来解析响应并将其作为错误数据类的实例

 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)
    }

我希望它有帮助

于 2020-07-07T15:21:54.127 回答
1

以防万一这有助于其他人在这个空间中搜索,在我的 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)

    ...

  }

}
于 2020-12-28T14:23:15.177 回答
0

花了几个小时后,我通过以下步骤得到了错误正文。

1. 为错误定义模型类。就我而言,它类似于

@Serializable
data class MyException(
    val message : String,
    val code : String,
    val type : String,
    val status_code : Int
) : RuntimeException()

您可以看到我还将自定义类扩展到 RuntimeException,因为我希望我的类表现得像 Exception 类

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))
}

就是这样。您已经解析了错误正文。

要简明扼要地理解它,您只需要集中在两个步骤中。

1. val res = ex.response.readText(Charsets.UTF_8)

2. val myException = Json { ignoreUnknownKeys = true }.decodeFromString(MyException.serializer(), res)

于 2021-06-06T12:26:39.480 回答