【安卓】在拦截器中结束这此请求的响应

文章描述了一位开发者在使用Retrofit进行网络请求时遇到的问题,即在拦截器中处理特定result_code时,仍会弹出未预期的Toast。经过分析,发现是因为拦截器返回了原始响应,导致不符合条件的请求触发了错误处理。解决方案是抛出自定义异常,在onError方法中捕获并处理,以避免错误提示。
摘要由CSDN通过智能技术生成

一、项目背景

在项目原有的MVVM架构中,所有的请求都是调用一个封装好的retrofit网络请求工具类,在Repository请求的响应中进行初步解析,通过result_codereturn_code同时为01进行判断,true则返回响应结果,false弹出Toast展示return_msg

补充:在所有请求响应中,必须包含result_codereturn_code其中之一,否则视为请求失败

二、项目需求

在此次的需求中,产品希望我们可以完成这样一个功能,在接收到指定的result_code时,打开一个新的页面,为了保证不留死角,产品要求所有请求甚至大部分请求都要能处理这一响应。

三、开发目标

1、满足产品的要求;

2、保护开发的头发;

3、保证代码的健壮性。

四、阴影中环伺的bug

第一套方案:

考虑到上述三个目标,我在开发中使用了拦截器的写法,即在进行网络请求时添加一个拦截器,在chain中获取请求响应,当拿到响应中的result_code,根据result_code的状态进行判断,符合要求的话就进入指定的页面。

//省略部分代码
@Singleton
class NewInterceptor @Inject constructor(
    //...
) : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
		//...
         try {
         	//...
            when (jsonObject.get("result_code").toString()) {
                "100"->EventBus.getDefault().post(NewEvent(jsonObject.get("return_msg").toString() ?: ""))
            } 
         } catch (e: Exception) {
           		e.printStackTrace()
           }

        }
        return originalResponse
    }

}

这个方案看起来很不错,能完美的完成上诉三个需求,也不用逐个Repository中做判断,但按照这个方案实施后,发现新打开的页面总会出现一个Toast,且这个Toast显示的信息是result_msg

在排除了新页面可能存在的干扰后,我对这个bug进行了初步判断:

由于在代码中有些网络请求的响应参数没有接收result_code,所以初步怀疑是由于拦截器没有拦截到此类情况,在后续的响应流程中,代码没有满足开始的条件,所以弹出了return_msg

根据这个判断,我优化了第一套方案的判断逻辑。

第二套方案

在第一套方案的基础上,我们增加一个对于return_msg的判断(此判断方式十分不好,非必要不要使用,这里是所有请求的msg统一才使用的),当msg包含指定文本时,也要进入上述逻辑。现在我们的判断逻辑就是:

result_code的状态符合要求return_msg包含指定文本时时,跳转到指定页面。

//省略部分代码
@Singleton
class NewInterceptor @Inject constructor(
    //...
) : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
		//...
         try {
         	//...
            if(isResultCodeCondition(jsonObject.get("result_code").toString()) || isMsgCondition(jsonObject.get("return_msg").toString())) {
                EventBus.getDefault().post(NewEvent(jsonObject.get("return_msg").toString() ?: ""))
            } 
         } catch (e: Exception) {
           		e.printStackTrace()
           }

        }
        return originalResponse
    }
    
	fun isResultCodeCondition(code: String): Boolean {
        return when (code) {
            "100", "101" -> true
            else -> false
        }
    }

    fun isMsgCondition(msg: String): Boolean {
        return msg.contains("符合的文本")
    }

}

改好再运行后,发现Toast依然弹出,说明初步判断的原因不是此次bug的关键原因,我们接着继续分析,如果你足够细心的话,你会注意到在上面的代码块中有这样一行代码:

return originalResponse

这意味着在上面的逻辑执行完后,拦截器依然返回了响应,继续往下分析,拦截器返回响应,又由于return_code不符合项目背景中的标准,导致弹出toast提示。

这一下,逻辑就通顺了,接着改吧,首先想到的是在拦截到指定条件后取消这次请求,于是第三套方案出现了:

第三套方案

if(isResultCodeCondition(jsonObject.get("result_code").toString()) || isMsgCondition(jsonObject.get("return_msg").toString())) {
                EventBus.getDefault().post(NewEvent(jsonObject.get("return_msg").toString() ?: ""))
                //取消请求
                chain.call().cancel()
            } 

运行后我们发现,坏消息是:toast依然存在,好消息是:这次的toast提示的是“网络请求异常”,这个提示是在我们封装的网络请求工具类的**onError()**方法中响应的。这说明我们思路对了,果然是最后的那行代码导致的问题,那么怎么解决这个问题呢。

我们先来明确一下现在的问题:

首先,我们肯定是不能定义成没有返回的拦截器的,这样会导致正常的请求没有返回响应。

其次,直接取消请求会进入onError流程,也会弹出一个提示

比较简单的方案是,在拦截到指定条件后,抛出一个异常,再在onError()方法中判断异常,让我们定义的异常不做处理。我们这里采用这个方案。

最终方案

val isCapture = try {
    //...
    if(isResultCodeCondition(jsonObject.get("result_code").toString()) || isMsgCondition(jsonObject.get("return_msg").toString())) {
         EventBus.getDefault().post(NewEvent(jsonObject.get("return_msg").toString() ?: ""))
         true
    } else {
         false
    }
} catch (e: Exception) {
      e.printStackTrace()
      false
}
if (isCapture) {
	//抛出自定义异常
   throw NewException()
}

总结

记录开发中遇到的bug,遇到的情形越多,开发时能考虑的情况和细节也就越多,类比于修仙,此之谓:斧凿道心。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值