gpt4 book ai didi

android - 网络错误改造的异常处理

转载 作者:行者123 更新时间:2023-11-29 16:28:34 25 4
gpt4 key购买 nike

我想知道在使用协程时处理改进请求中的网络错误的最佳方法是什么。

经典方法是在发出请求时在最高级别处理异常:

try {
// retrofit request
} catch(e: NetworkException) {
// show some error message
}

我发现这个解决方案是错误的,它添加了很多样板代码,相反我创建了一个返回错误响应的拦截器:

class ErrorResponse : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
return try {
chain.proceed(request)
} catch (e: Exception) {
Snackbar.make(
view,
context.resources.getText(R.string.network_error),
Snackbar.LENGTH_LONG
).show()
Response.Builder()
.request(request)
.protocol(Protocol.HTTP_1_1)
.code(599)
.message(e.message!!)
.body(ResponseBody.create(null, e.message!!))
.build()
}
}
}

这个解决方案稍微好一点,但我认为它可以改进。

所以我的问题是:当用户没有互联网连接且没有大量样板代码(理想情况下使用全局处理程序以防出现连接错误)时,处理这种情况的正确方法是什么?

最佳答案

使用 Result 来包装我的响应

sealed class Result<out T : Any> {
data class Success<out T : Any>(val value: T) : Result<T>()
data class Failure(val errorHolder:ErrorHolder) : Result<Nothing>()}

错误持有者:

sealed class ErrorHolder(override val message):Throwable(message){
data class NetworkConnection(override val message: String) : ErrorHolder(message)
data class BadRequest(override val message: String) : ErrorHolder(message)
data class UnAuthorized(override val message: String) : ErrorHolder(message)
data class InternalServerError(override val message: String) :ErrorHolder(message)
data class ResourceNotFound(override val message: String) : ErrorHolder(message)
}

处理异常的扩展

suspend fun <T, R> Call<T>.awaitResult(map: (T) -> R): Result<R> = suspendCancellableCoroutine { continuation ->
try {
enqueue(object : Callback<T> {
override fun onFailure(call: Call<T>, throwable: Throwable) {
errorHappened(throwable)
}

override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
try {
continuation.resume(Result.Success(map(response.body()!!)))
} catch (throwable: Throwable) {
errorHappened(throwable)
}
} else {
errorHappened(HttpException(response))
}
}

private fun errorHappened(throwable: Throwable) {
continuation.resume(Result.Failure(asNetworkException(throwable)))
}
})
} catch (throwable: Throwable) {
continuation.resume(Result.Failure(asNetworkException(throwable)))
}

continuation.invokeOnCancellation {
cancel()
}}

这就是我调用 api 的方式:

suspend fun fetchUsers(): Result<List<User>> {
return service.getUsers().awaitResult { usersResponseDto ->
usersResponseDto.toListOfUsers()
}
}

更新:

假设您有如下错误正文:

{
"error" : {
"status" : 502,
"message" : "Bad gateway."
}
}

首先我们应该创建一个数据类来模拟响应主体

data class HttpErrorEntity(
@SerializedName("message") val errorMessage: String,
@SerializedName("status") val errorCode: Int
)

这里是 asNetworkException 实现:

private fun asNetworkException(ex: Throwable): ErrorHolder {
return when (ex) {
is IOException -> {
ErrorHolder.NetworkConnection(
"No Internet Connection"
)
}
is HttpException -> extractHttpExceptions(ex)
else -> ErrorHolder.UnExpected("Something went wrong...")
}
}

private fun extractHttpExceptions(ex: HttpException): ErrorHolder {
val body = ex.response()?.errorBody()
val gson = GsonBuilder().create()
val responseBody= gson.fromJson(body.toString(), JsonObject::class.java)
val errorEntity = gson.fromJson(responseBody, HttpErrorEntity::class.java)
return when (errorEntity.errorCode) {
ErrorCodes.BAD_REQUEST.code ->
ErrorHolder.BadRequest(errorEntity.errorMessage)

ErrorCodes.INTERNAL_SERVER.code ->
ErrorHolder.InternalServerError(errorEntity.errorMessage)

ErrorCodes.UNAUTHORIZED.code ->
ErrorHolder.UnAuthorized(errorEntity.errorMessage)

ErrorCodes.NOT_FOUND.code ->
ErrorHolder.ResourceNotFound(errorEntity.errorMessage)

else ->
ErrorHolder.Unknown(errorEntity.errorMessage)

}
}

关于android - 网络错误改造的异常处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58523119/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com