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

使用Retrofit调用AWS Appsync GraphQL接口返回400错误如何解决?

问题根因排查

你当前的代码存在两个核心错误,是导致400错误的直接原因:

  • Content-Type和请求Body格式不匹配:如果设置Content-Type: application/graphql,请求Body应该直接是GraphQL查询字符串,不需要外层包裹{"query": ...}的JSON结构;如果要传JSON结构的请求体,Content-Type应该改为application/json。AWS AppSync本身同时兼容两种请求格式,但你的Android代码把两种格式混用,导致服务端解析失败。
  • Retrofit String类型Body的序列化错误:你配置了GsonConverterFactory,当你传入String类型的对象作为@Body时,Gson会自动给字符串添加双引号、转义内部特殊字符,最终发出的请求体不是你预期的结构,而是被二次转义的字符串。

方案1:使用application/json格式请求(推荐,和NodeJS逻辑完全对齐)

1. 修改GraphqlService接口

public interface GraphqlService {
    @Headers({
            "Content-Type: application/json",
            "x-api-key: SOME_API_KEY"
    })
    @POST("/graphql")
    // 改用RequestBody避免Gson二次序列化
    Call<String> getLockers(@Body RequestBody body);
}

2. 修改请求发起逻辑

retrofit = new Retrofit.Builder()
        .baseUrl("https://amazon.endpoint.com")
        .addConverterFactory(GsonConverterFactory.create())
        .build();
GraphqlService service = retrofit.create(GraphqlService.class);

try {
    JSONObject paramObject = new JSONObject();
    String query = "query { listData { dataName } }";
    paramObject.put("query", query);
    // 直接构建JSON类型的RequestBody,跳过Gson二次处理
    RequestBody body = RequestBody.create(
        paramObject.toString(),
        MediaType.parse("application/json; charset=utf-8")
    );
    service.getLockers(body)
            .enqueue(new Callback<String>() {
                @Override
                public void onResponse(Call<String> call, Response<String> response) {
                    System.out.println(response);
                }

                @Override
                public void onFailure(Call<String> call, Throwable t) {
                    System.out.println(t);
                }
            });
} catch (JSONException e) {
    e.printStackTrace();
}

可选优化

可以封装请求实体类避免每次手动拼接JSON:

public class GraphqlRequest {
    private String query;
    // 有查询变量的话可以再加个Map<String, Object> variables字段

    public GraphqlRequest(String query) {
        this.query = query;
    }

    // 按需添加get、set方法
}

接口定义改为Call<String> getLockers(@Body GraphqlRequest request);,调用时直接传入实体类对象即可,Gson会自动序列化为正确的JSON结构,代码更简洁。


方案2:使用application/graphql格式请求

如果要保持Content-Type为application/graphql,直接传查询字符串即可,不需要外层JSON包裹:

1. 修改GraphqlService接口

public interface GraphqlService {
    @Headers({
            "Content-Type: application/graphql",
            "x-api-key: SOME_API_KEY"
    })
    @POST("/graphql")
    Call<String> getLockers(@Body RequestBody body);
}

2. 修改请求发起逻辑

// 直接传查询字符串作为Body
RequestBody body = RequestBody.create(
    "query { listData { dataName } }",
    MediaType.parse("application/graphql; charset=utf-8")
);
// 其余请求逻辑和方案1一致

调试建议

如果修改后依然报错,可以接入OkHttp的LoggingInterceptor拦截器,设置日志级别为BODY,打印完整的请求头、请求体内容,和curl的请求内容做对比,就能快速定位差异点。

内容的提问来源于stack exchange,提问作者Trayson Keli'i

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 12:18:03