You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Retrofit请求报错:Expected BEGIN_OBJECT but was STRING求助

解决Retrofit+Gson解析时的JsonSyntaxException问题

看起来你遇到的错误根源有两个:请求体格式不符合服务器预期,以及响应模型和服务器返回的JSON结构不匹配,咱们一步步来修复:

1. 错误原因分析

  • 先看报错信息:Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $,这说明Gson尝试解析JSON对象,但收到的却是纯字符串(大概率是服务器返回的错误提示,因为请求格式不对)。
  • 你的接口getCashCollection直接把String类型的guid作为@Body传递,这会让Retrofit发送纯文本字符串(比如"xxxx-guid-xxxx"),而非服务器期望的JSON对象格式(比如{"guid": "xxxx-guid-xxxx"}),服务器无法正确处理请求,返回了非预期的字符串响应,导致Gson解析失败。
  • 退一步说,就算请求正确,服务器返回的JSON是包含data数组和currency字段的对象,但你定义的接口返回Call<List<CashCollection>>,Gson没法把外层对象直接解析成List,这也会触发解析错误。

2. 具体修复步骤

步骤一:创建请求体模型类

用一个类包裹guid,让Retrofit发送符合要求的JSON请求体:

data class CashCollectionRequest(
    val guid: String
)

步骤二:修改API接口定义

更新接口,使用新的请求体类,同时把返回类型改成匹配服务器响应的模型:

interface ChartsDataApi {
    @POST(NetworkUtils.CASH_COLLECTION_URL)
    // 替换String为请求体类,返回类型改为响应模型
    fun getCashCollection(@Body request: CashCollectionRequest) : Call<CashCollectionResponse>
    
    @POST(NetworkUtils.TICKETS_DETAILS_URL)
    fun getTicketsDetails() : Call<List<TicketDetails>>
}

步骤三:创建响应模型类

这个类要完全匹配服务器返回的JSON结构:

data class CashCollectionResponse(
    @SerializedName("data") val data: List<CashCollection>,
    @SerializedName("currency") val currency: String?
)

// 你的CashCollection类可以保留不变
data class CashCollection(
    @SerializedName("label") val label: String?,
    @SerializedName("value") val value: String?
)

步骤四:更新请求实现代码

调整请求调用和响应解析的逻辑:

private fun geCashCollectionDetails(){
    val BASE_URL = "这里填写了基础URL"
    val gson = GsonBuilder()
        .setLenient()
        .create()
    val api = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()
        .create(ChartsDataApi::class.java)
    
    GlobalScope.launch(Dispatchers.IO){
        // 传入请求体对象
        val response = api.getCashCollection(CashCollectionRequest("这里填写了guid")).awaitResponse()
        if(response.isSuccessful){
            // 从响应模型中获取data列表
            val cashCollectionList = response.body()?.data ?: emptyList()
            val day = cashCollectionList.lastIndex
            Log.d("RAZZ", day.toString())
            
            withContext(Dispatchers.Main){
                // 这里可以添加UI更新逻辑
            }
        } else {
            // 处理请求失败的情况,比如打印错误信息
            Log.e("RAZZ", "Request failed: ${response.errorBody()?.string()}")
        }
    }
}

3. 额外注意点

  • 如果服务器要求请求体的字段名不是guid,记得给CashCollectionRequest的字段加上@SerializedName注解,比如@SerializedName("user_guid") val guid: String。
  • 建议不要直接用GlobalScope,可以自定义CoroutineScope,避免内存泄漏问题。
  • 测试时可以用抓包工具(比如Charles)确认请求体格式是否正确,以及服务器返回的响应是否符合预期。

内容的提问来源于stack exchange,提问作者Razvan Andrei

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 16:42:30