Escribí un código común en un módulo común como se muestra a continuación y lo probé en un entorno JS
val response = client.post<HttpResponse>(url) { body = TextContent("""{"a":1,"b":2}""", ContentType.Application.Json) } if (response.status != HttpStatusCode.OK) { logger.error("Error, this one failed bad?") }Pero mi código termina en client.post con una corutineException cancelada en ninguna red. ¿Cómo manejo esta y cualquier otra excepción? Si hay conexión a internet. Nada falla, quiero poder manejar las excepciones. ¿Cómo?
Nota: intente, catch no funciona
No agrego mucho a la respuesta actual, pero en respuesta al comentario de CVS, he estado usando lo siguiente para agregar el manejo de errores del cliente ktor en mis aplicaciones. Hace uso de la API de resultados . runCatching {} captura todos los Throwable s y puede modificar el comportamiento del bloque getOrElse para capturar las excepciones que le interesan.
suspend fun <T> HttpClient.requestAndCatch( block: suspend HttpClient.() -> T, errorHandler: suspend ResponseException.() -> T ): T = runCatching { block() } .getOrElse { when (it) { is ResponseException -> it.errorHandler() else -> throw it } } // Example call client.requestAndCatch( { get<String>("/") }, { when (response.status) { HttpStatusCode.BadRequest -> {} // Throw errors or transform to T HttpStatusCode.Conflict -> {} else -> throw this } } )Estoy seguro de que podría hacerse más ordenado, pero es lo mejor que he encontrado hasta ahora.
Bueno, después de preguntar aquí y allá, obtuve ayuda de problemas de github y vine a este trabajo.
try { val response = client.post<HttpResponse>(url) { body = TextContent("""{"a":1,"b":2}""", ContentType.Application.Json) } if (response.status != HttpStatusCode.OK) { logger.error("Error, this one failed bad?") } } catch (cause: Throwable) { logger.error("Catch your error here") } no confunda catch (c: Throwable) con catch (e: Exception)
espero que esto ayude
Podemos manejarlo de manera central usando esta función de extensión que envuelve los casos de éxito y error. Podemos tener errores de red, errores de serialización o errores del servidor que pueden exponer cuerpos/mensajes de error para la interfaz de usuario y el código de estado http.
suspend inline fun <reified T, reified E> HttpClient.safeRequest( block: HttpRequestBuilder.() -> Unit, ): ApiResponse<T, E> = try { val response = request { block() } ApiResponse.Success(response.body()) } catch (e: ClientRequestException) { ApiResponse.Error.HttpError(e.response.status.value, e.errorBody()) } catch (e: ServerResponseException) { ApiResponse.Error.HttpError(e.response.status.value, e.errorBody()) } catch (e: IOException) { ApiResponse.Error.NetworkError } catch (e: SerializationException) { ApiResponse.Error.SerializationError } suspend inline fun <reified E> ResponseException.errorBody(): E? = try { response.body() } catch (e: SerializationException) { null } Aquí está la ApiResponse definida a continuación, por lo que hay un código de trabajo:
sealed class ApiResponse<out T, out E> { /** * Represents successful network responses (2xx). */ data class Success<T>(val body: T) : ApiResponse<T, Nothing>() sealed class Error<E> : ApiResponse<Nothing, E>() { /** * Represents server (50x) and client (40x) errors. */ data class HttpError<E>(val code: Int, val errorBody: E?) : Error<E>() /** * Represent IOExceptions and connectivity issues. */ object NetworkError : Error<Nothing>() /** * Represent SerializationExceptions. */ object SerializationError : Error<Nothing>() } } Descubrí que ApiResponse funciona bien para mi caso, pero no necesariamente tiene que modelar sus respuestas api como este si tiene otros casos/casos especiales, también puede usar kotlin-result o Arrow's Any .