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

Android中Retrofit集成GraphQL API报400错误,请求排查

解决Retrofit调用GraphQL API返回400错误的问题

核心问题是请求体的JSON结构错误:你把包含operationName、variables、query的完整请求内容嵌套到了"query"这个key下,而GraphQL服务器期望这三个字段是顶级字段,这直接导致服务器无法解析请求,返回400错误。

修正步骤

1. 直接构造正确的JSON请求体

不要将整个请求内容放到"query"字段中,而是直接给JSONObject添加三个顶级字段:

private fun getAllEquipments() {
    val retrofit = GraphQLInstance.graphQLService
    // 提取查询字符串,用Kotlin三重引号避免转义混乱
    val queryStr = """
        query MyQuery {
          listEquipment(query: {query: "{              }", page: 1, search: "", size: 25}) {
            items {
              id
              name
              image
              equipment_type_name
              category_name
              property_name
              specific_location
              manufacturer_name
              model_name
              age
            }
            page
            size
            total
          }
        }
    """.trimIndent()

    val paramObject = JSONObject()
    paramObject.put("operationName", "MyQuery")
    paramObject.put("variables", JSONObject()) // 空变量用空JSON对象
    paramObject.put("query", queryStr)

    // 建议使用生命周期绑定的CoroutineScope,而非GlobalScope
    lifecycleScope.launch {
        try {
            val response = retrofit.getEquipmentList(deliveryToken, apiKey, "web", paramObject.toString())
            Log.e("response code >>", response.code().toString())
            if (response.code() == 400) {
                // 可以尝试解析errorBody的具体内容,获取更详细的错误信息
                val errorMsg = response.errorBody()?.string()
                Log.v("Error code 400", errorMsg ?: "无详细错误信息")
            }
            Log.e("response ", response.raw().toString())
            Log.e("response body", response.body().toString())
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

2. 更优方案:用数据类+Gson转换器避免手动拼接JSON

手动拼接JSON容易出错,推荐定义数据类配合GsonConverterFactory,让Retrofit自动序列化请求体:

第一步:定义GraphQL请求数据类

data class GraphQLRequest(
    val operationName: String,
    val variables: Map<String, Any>,
    val query: String
)

第二步:修改Retrofit接口

将@Body的参数类型从String改为GraphQLRequest:

@Headers("Content-Type: application/json")
@POST("graphql/")
suspend fun getEquipmentList(
    @Header("Authorization") token: String?,
    @Header("x-api-key") apiKey: String?,
    @Header("x-schema") schema: String?,
    @Body body: GraphQLRequest
): Response<String>

第三步:更新Retrofit实例,添加Gson转换器

object GraphQLInstance {
    private const val BASE_URL: String = "https://myUrl.amazonaws.com/"
    val graphQLService: GraphQLService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create()) // 添加Gson转换器
            .addConverterFactory(ScalarsConverterFactory.create())
            .build()
            .create(GraphQLService::class.java)
    }
}

第四步:调用接口

private fun getAllEquipments() {
    val retrofit = GraphQLInstance.graphQLService
    val queryStr = """
        query MyQuery {
          listEquipment(query: {query: "{              }", page: 1, search: "", size: 25}) {
            items {
              id
              name
              image
              equipment_type_name
              category_name
              property_name
              specific_location
              manufacturer_name
              model_name
              age
            }
            page
            size
            total
          }
        }
    """.trimIndent()

    val request = GraphQLRequest(
        operationName = "MyQuery",
        variables = emptyMap(),
        query = queryStr
    )

    lifecycleScope.launch {
        try {
            val response = retrofit.getEquipmentList(deliveryToken, apiKey, "web", request)
            // 后续日志处理同之前
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

额外提示

  • 避免使用GlobalScope,推荐使用与页面/组件生命周期绑定的lifecycleScope或viewModelScope,防止内存泄漏。
  • 当收到400错误时,可以尝试解析errorBody()?.string()获取服务器返回的具体错误信息,帮助定位问题。

内容的提问来源于stack exchange,提问作者Manikandan Balakrishnan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 11:05:38