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
相关产品推荐
相关产品推荐

