从HttpURLConnection迁移至Retrofit2遇到Gson解析异常问题
解决Retrofit2 + GsonConverterFactory 遇到的 Expected BEGIN_OBJECT 错误
我之前也碰到过几乎一模一样的问题——旧代码手动用GZipInputStream解压能正常解析JSON,换成Retrofit就直接报格式错误,核心原因大概率是Retrofit没有自动处理Gzip压缩的响应,导致Gson拿到的是原始压缩字节流,根本不是合法的JSON字符串,自然会触发"Expected BEGIN_OBJECT"的报错。下面给你一步步排查解决:
1. 先确认服务器响应的压缩状态
先用Postman或者浏览器调用目标接口,检查响应头里是否存在 Content-Encoding: gzip。如果有这个字段,说明服务器返回的是Gzip压缩后的内容,这时候Retrofit必须配置解压逻辑才能正确读取JSON。
2. 给OkHttpClient配置Gzip解压支持
Retrofit依赖OkHttp,OkHttp本身有内置的Gzip处理能力,但如果你自定义了OkHttpClient实例,可能需要显式配置确保生效:
OkHttpClient client = new OkHttpClient.Builder() // 显式添加请求头,告诉服务器我们接受Gzip压缩的响应 .addInterceptor(chain -> { Request compressedRequest = chain.request().newBuilder() .header("Accept-Encoding", "gzip") .build(); return chain.proceed(compressedRequest); }) // OkHttp 4+ 可以直接用内置的Gzip请求拦截器,写法更简洁: // .addInterceptor(new GzipRequestInterceptor()) .build();
然后把这个配置好的client传给Retrofit:
Retrofit retrofit = new Retrofit.Builder() .baseUrl("你的服务器基础地址") .client(client) .addConverterFactory(GsonConverterFactory.create()) .build();
3. 检查实体类与JSON结构的匹配度
虽然旧代码能手动解析,但要确保你的实体类完全对应JSON的结构:
- 如果JSON是
{...}格式的单个对象,接口返回类型必须是Call<YourEntity>,不能写成Call<List<YourEntity>> - 字段名要和JSON键一致,或者用
@SerializedName注解做映射,比如:
假设你的JSON是:
{ "user_id": 1001, "user_name": "Mike" }
对应的实体类应该是:
public class User { @SerializedName("user_id") private int userId; @SerializedName("user_name") private String userName; // 记得添加getter/setter方法 }
4. 排查拦截器的执行顺序
如果你还添加了日志拦截器(比如HttpLoggingInterceptor),一定要把它放在Gzip拦截器之后,避免日志拦截器提前读取压缩流,导致后续解压逻辑无法正常获取数据。
最后验证
配置完成后,用日志拦截器打印响应体,如果你能看到以{开头的正常JSON字符串,说明解压已经生效,Gson就能自动映射到实体类了。
内容的提问来源于stack exchange,提问作者Mike6679
相关产品推荐
相关产品推荐

