Android Kotlin和改造:如何处理HTTP 400响应?

Android Kotlin和改造:如何处理HTTP 400响应?,android,kotlin,retrofit,okhttp,Android,Kotlin,Retrofit,Okhttp,我正在使用安卓系统上的改造(2.6)来实现一个连接到web服务器的服务,该服务要求服务器承担一些工作。相关代码可概括如下: interface MyService { @GET(START_WORK) suspend fun startWork(@Query("uuid") uuid: String, @Query("mode") mode: Int): MyStartWorkResponse } // Do

我正在使用安卓系统上的改造(2.6)来实现一个连接到web服务器的服务,该服务要求服务器承担一些工作。相关代码可概括如下:

interface MyService {
    @GET(START_WORK)
    suspend fun startWork(@Query("uuid") uuid: String,
                          @Query("mode") mode: Int):
        MyStartWorkResponse
}

// Do some other things, include get a reference to a properly configured
// instance of Retrofit.

// Instantiate service
var service: MyService = retrofit.create(MyService::class.java)
我可以毫无问题地调用
service.startWork()
,并获得有效的结果。但是,在某些情况下,web服务器将返回400错误代码,并返回包含特定错误信息的响应正文。但是,请求的格式没有错误;只是还有一个问题需要引起用户的注意。问题是,我不知道问题出在哪里,因为我没有得到回应;相反,我的调用抛出一个异常,因为错误代码为400


我不知道如何修改我的代码,以便捕获和处理400个错误响应,并从响应主体中获取所需的信息。这是我的okhttp客户端上的网络拦截器的作业吗?有人能解释一下吗?

改装将成功响应定义为:

公共布尔值isSuccessful(){ 返回代码>=200&&code<300;}

这意味着你应该可以做这样的事情

class ServiceImpl(private val myService: MyService) {
   suspend fun startWork(//query): MyResponse =

    myService.startWork(query).await().let {

    if (response.isSuccessful) {
        return MyResponse(response.body()//transform
                ?: //some empty object)
    } else {
        throw HttpException(response)//or handle - whatever
    }
}

}
使用此代码(KOTLIN)

类ApiClient{
伴星{
private val BASE\u URL=“您的\u URL\u服务器”
专用var改装:改装?=null
private val okHttpClientvalor=OkHttpClient.Builder()
.connectTimeout(90,时间单位为秒)
.writeTimeout(90,时间单位。秒)
.readTimeout(90,时间单位为秒)
.build()
fun ApicClient():改装{
如果(改装==null){
改装=改装.Builder().baseUrl(基本URL)
.客户(okHttpClientvalor)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
返修!!
}
}
}
对象错误{
错误(响应:响应):错误响应一次{
val conversorDeErro=ApiClient.ApiClient()
.responseBodyConverter(ErrorResponse::class.java,arrayOfNulls(0))
var errorResponse:errorResponse?=null
试一试{
if(response.errorBody()!=null){
ErrorResponse=conversorderro.convert(response.errorBody()!!)
}
}捕获(e:IOException){
返回errorResponse()
}最后{
返回错误响应一次
}
}
}
类错误响应一次{
/*此名称“error”必须与服务器返回的消息密钥匹配。
示例:{“错误”:“错误请求…”*/
@SerializedName(“错误”)
@暴露
变量错误:字符串?=null
}
if(response.issucessful){
返回MyResponse(response.body()//转换
?://一些空对象)
}否则{
val errorresponse=ErrorUtils.parseError(响应)
errorResponce!!.error?.let{message->
Toast.makeText(this,message,Toast.LENGTH\u SHORT).show()
}
}

谢谢你的建议!不过,我不知道我如何能够通过改装获得对
响应的引用。当我们到达这一点时,调用不是已经失败了吗?它将失败但不会引发异常-并且您应该能够通过errorBody读取正文-公共静态响应错误(ResponseBody body,okhttp3.Response rawResponse){checkNotNull(body,“body==null”);checkNotNull(rawResponse,“rawResponse==null”);if(rawResponse.issusccessful()){throw new IllegalArgumentException(“rawResponse不应该是成功的响应”);}返回新的响应(rawResponse,null,body);}为了调用
await(),
MyResponse
需要继承什么
响应。isSuccessful
?MyResponse是您的自定义模型-您可以转换。总的来说,这里有一个结构示例:/service interface MyService{@GET(“whatever”)fun getSomething(@Query(value=“whater)id:Int):Deferred}//repository interface MyRepository{suspend fun getSomething(id:Int):List}//repos impl类MyRepositoryImpl(private val MyService:MyService):MyRepository{override suspend fun getSomething(id:Int):List=myService.getSomething(id).await().let{it}}这是一个很好的模式示例-
class ApiClient {

    companion object {

        private val BASE_URL = "YOUR_URL_SERVER"
        private var retrofit: Retrofit? = null

        private val okHttpClientvalor = OkHttpClient.Builder()
            .connectTimeout(90, TimeUnit.SECONDS)
            .writeTimeout(90, TimeUnit.SECONDS)
            .readTimeout(90, TimeUnit.SECONDS)
            .build()

        fun apiClient(): Retrofit {
            if (retrofit == null) {
                retrofit = Retrofit.Builder().baseUrl(BASE_URL)
                    .client(okHttpClientvalor)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
            }
            return retrofit!!
        }

    }

}


object ErrorUtils {

    fun parseError(response: Response<*>): ErrorResponce? {
        val conversorDeErro = ApiClient.apiClient()
            .responseBodyConverter<ErrorResponce>(ErrorResponce::class.java, arrayOfNulls(0))
        var errorResponce: ErrorResponce? = null
        try {
            if (response.errorBody() != null) {
                errorResponce = conversorDeErro.convert(response.errorBody()!!)
            }
        } catch (e: IOException) {
            return ErrorResponce()
        } finally {
            return errorResponce
        }
    }
}


class ErrorResponce {
     /* This name "error" must match the message key returned by the server.
  Example: {"error": "Bad Request ....."} */
    @SerializedName("error")
    @Expose
    var error: String? = null
}

    if (response.isSuccessful) {
        return MyResponse(response.body()  // transform
                ?:  // some empty object)
    } else {
        val errorResponce = ErrorUtils.parseError(response)
        errorResponce!!.error?.let { message ->
        Toast.makeText(this,message,Toast.LENGTH_SHORT).show()
    }
}