You need to enable JavaScript to run this app. Android Retrofit处理登录接口同时返回JSON或String响应的解决方案求助
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 08:54:03