【问题标题】:Kotlin and Retrofit : How to Handle HTTP 400 responses?Kotlin 和 Retrofit:如何处理 HTTP 400 响应?
【发布时间】:2020-04-26 11:30:49
【问题描述】:

我在 Android 上使用 Retrofit (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 客户端上的网络拦截器的工作吗?有人能解释一下吗?

【问题讨论】:

    标签: android kotlin retrofit okhttp


    【解决方案1】:

    Retrofit 将成功响应定义为:

    public boolean isSuccessful() { 返回代码 >= 200 && 代码

    这意味着你应该能够做这样的事情

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

    【讨论】:

    • 感谢您的建议!不过,我看不出我如何能够连接到 Retrofit 以获取对 response 的引用。到了这一步,电话不是已经失败了吗?
    • 它会失败但不会抛出异常 - 你应该能够通过 errorBody 读取正文 - public static Response error(ResponseBody body, okhttp3.Response rawResponse) { checkNotNull (body, "body == null"); checkNotNull(rawResponse, "rawResponse == null"); if (rawResponse.isSuccessful()) { throw new IllegalArgumentException("rawResponse 不应该是成功响应"); } return new Response(rawResponse, null, body); }
    • MyResponse 需要继承什么才能让我调用await()response.isSuccessful
    • MyResponse 是您的自定义模型 - 您可以转换。总的来说这里是一个结构示例: /service interface MyService { @GET( "whatever") fun getSomething(@Query(value="whatever) id: Int): Deferred> } //repository interface MyRepository { suspend fun getSomething(id: Int): List } //repos impl class MyRepositoryImpl (private val myService: MyService) : MyRepository { override suspend fun getSomething(id: Int): List = myService.getSomething( id).await().let { 它 } }
    • 这里是这种模式的一个很好的例子 - github.com/fabioCollini/ArchitectureComponentsDemo/blob/master/…
    【解决方案2】:

    使用此代码 (KOTLIN)

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

    【讨论】:

      猜你喜欢
      • 2016-03-04
      • 1970-01-01
      • 2020-04-25
      • 2017-05-01
      • 1970-01-01
      • 2020-05-14
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多