Android使用Retrofit解析JSON出现Expected BEGIN_OBJECT错误如何解决
错误原因分析
该报错核心含义是Gson解析时预期根节点为JSON对象,但实际接收到的根节点是字符串类型,结合提供的代码,可能的触发原因如下:
- 接口实际返回内容不是Postman拿到的JSON结构,服务端在参数错误、鉴权失败时直接返回了纯文本错误提示,没有包裹JSON结构
- 代码调用接口时传的参数和Postman不一致,尤其是apiKey、时间参数(代码里传的请求时间是0500,Postman拿到的响应里baseTime是1100,参数不匹配会触发服务端返回非JSON的错误响应)
- 服务端开启了UA校验、反爬规则,移动端请求时返回了HTML/纯文本的拦截提示,而非正常JSON
- 次要排查项:
@Expose注解未配合Gson配置生效,不过该问题不会触发根节点的解析错误
解决步骤
- 先打印接口返回的原始响应内容,确认实际返回的结构
给Retrofit添加日志拦截器,查看完整的请求和响应内容,首先添加依赖(如未添加):
implementation 'com.squareup.okhttp3:logging-interceptor:4.10.0'
修改RetrofitService的代码,添加日志拦截器:
public class RetrofitService { public Retrofit getRetroInstance(String baseUrl){ // 添加日志拦截器打印完整请求响应 HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .build(); Gson gson = new GsonBuilder() .setLenient() .excludeFieldsWithoutExposeAnnotation() // 配合@Expose注解过滤不需要序列化的字段 .create(); return new Retrofit.Builder() .baseUrl(baseUrl) .client(client) .addConverterFactory(GsonConverterFactory.create(gson)) .build(); } }
- 校验请求参数和Postman完全一致:确认代码里传的apiKey、请求日期、请求时间参数和Postman调用时用的参数完全相同,避免参数错误导致服务端返回非JSON响应
- 如果确认服务端有时会返回字符串类型的错误响应,可以先把Retrofit的响应类型改成
ResponseBody,手动判断响应格式再做解析:
修改接口请求的返回类型为Call<ResponseBody>,收到响应后先转成字符串,判断是JSON结构再用Gson转成ShortWeather对象,否则直接处理错误字符串:
Call<ResponseBody> call = MaAPI.getShortWeather("你的正式apiKey", 50,1,"JSON","20210904","1100",55,127); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if(response.isSuccessful() && response.body() != null){ try { String responseStr = response.body().string(); Log.d(TAG, "原始响应: " + responseStr); // 手动解析响应 Gson gson = new GsonBuilder().setLenient().create(); ShortWeather weather = gson.fromJson(responseStr, ShortWeather.class); data.postValue(weather); } catch (Exception e) { e.printStackTrace(); Log.d(TAG, "解析失败,原始响应不是合法JSON"); } } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.d(TAG,"onFailure : "+t.getMessage()); } });
- 额外校验:你定义的DTO类里已经通过
@SerializedName完成了JSON字段和类字段的映射,这部分逻辑正确,不需要修改。
内容的提问来源于stack exchange,提问作者codingRookie
相关产品推荐
相关产品推荐

