Android Retrofit处理登录接口同时返回JSON或String响应的解决方案求助
解决方案
出现该异常的核心原因是Retrofit会根据你声明的返回类型提前执行序列化转换,只要转换器顺序或返回类型设置不对,纯字符串响应就会在Gson解析阶段提前抛出异常,还未进入订阅回调就触发onError。可按以下方案处理:
- 第一步:修改API接口声明,直接返回
ResponseBody类型,避免Retrofit提前做序列化转换,将解析控制权完全放到业务代码中
@POST("api/v1/user/login") fun postLogin(@Body body: LoginBody): Observable<Response<ResponseBody>>
- 第二步:修改订阅逻辑,先读取响应体的字符串内容,再通过异常捕获区分两种格式分别处理
postLogin(LoginBody(username, password)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ response -> if (response.isSuccessful) { response.body()?.let { body -> // 注意:string()只能调用一次,必须先存为变量 val bodyStr = body.string() val res = try { // 先尝试按JSON格式解析为LoginRemote val loginRemote = Gson().fromJson(bodyStr, LoginRemote::class.java) LoginRemote.parseResponse(Response.success(loginRemote)) } catch (e: JsonSyntaxException) { // 解析失败说明是纯字符串响应,替换为你自己的字符串场景业务逻辑即可 LoginResponse(listOf(LoginResponse.ErrorType.StringResponse(bodyStr))) } // 原有业务逻辑保持不变 if (res.result is Result.Ok) { res.result.data.uid?.let { sessionData?.uid = it } res.result.data.username?.let { sessionData?.username = it } res.result.data.email?.let { sessionData?.email = it } res.result.data.phoneType?.let { sessionData?.phoneType = it } res.result.data.phone?.let { sessionData?.phone = it } res.result.data.verified?.let { sessionData?.verified = it } res.result.data.role?.let { sessionData?.role = it } res.result.data.gender?.let { sessionData?.gender = it } res.result.data.countryOfResidence?.let { sessionData?.countryOfResidence = it } } acceptTermsResponse.value = res } ?: run { acceptTermsResponse.value = LoginResponse(listOf(LoginResponse.ErrorType.Generic())) } } else { acceptTermsResponse.value = LoginResponse(listOf(LoginResponse.ErrorType.Generic())) } }, { acceptTermsResponse.value = LoginResponse(listOf(LoginResponse.ErrorType.Generic())) })
- 第三步:如果你希望通过Converter自动处理两种格式,需调整转换器注册顺序,将
ScalarsConverterFactory放在GsonConverterFactory之前,你之前添加Scalar转换器无效大概率是顺序放反了
val retrofit = Retrofit.Builder() .baseUrl(BASE_URL) // 注意顺序:Scalar转换器必须放在Gson转换器前面 .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) // 对应你使用的RxJava版本 .build()
注意:ResponseBody.string()方法仅可调用一次,调用后响应流会被关闭,必须先将返回值存入变量再做后续操作,不可重复调用
内容的提问来源于stack exchange,提问作者BlondeSwan
相关产品推荐
相关产品推荐

