Retrofit获取服务器数据报错:Expected BEGIN_OBJECT but was STRING 求解决
解决Retrofit解析报错:Expected BEGIN_OBJECT but was STRING
这个报错我太熟了——说白了就是你告诉Retrofit要解析成一个Java对象(比如User或者LoginResponse),但服务器返回的却是一段纯字符串,两者完全不匹配,Gson(Retrofit默认的解析器)根本没法把字符串转成对象,直接就炸了。下面给你一步步排查和解决的方案:
第一步:先搞清楚服务器到底返回了什么
先看你Postman请求的结果:
- 如果返回的是类似
"获取数据成功"、"用户不存在"这种纯文本,那问题根源就在这里; - 如果返回的是JSON,但开头不是
{(比如前面有空格、换行或者调试输出),那也会触发这个错误。
第二步:修复服务器端的输出(最关键)
你的index.php必须返回标准的JSON对象,而且不能有任何多余输出。举个正确的例子:
// 假设你从数据库拿到了用户数据 $user = array( "id" => 1, "username" => "Amir", "email" => "amir@example.com" ); // 必须设置这个响应头,告诉客户端这是JSON格式 header('Content-Type: application/json'); // 把数组转成JSON字符串输出 echo json_encode($user);
⚠️ 注意:PHP文件里绝对不能有<?php标签之前的空格、换行,也不能随便echo调试信息(比如echo "调试中..."),这些都会让返回的内容开头不是JSON对象的{,直接导致解析失败。
第三步:让Retrofit接口和返回的JSON结构匹配
如果服务器已经返回了正确的JSON对象,那要确保你的Retrofit接口返回类型和JSON结构完全对应:
比如服务器返回的是用户对象JSON,那接口应该这么写:
public interface ApiService { @GET("index.php") Call<User> getUserData(); }
对应的User类字段要和JSON的key完全一致(或者用@SerializedName映射):
public class User { private int id; private String username; private String email; // 别忘了写getter和setter,或者用Lombok简化 }
特殊情况:服务器可能返回字符串(比如错误提示)
如果服务器有时候返回JSON对象,有时候返回纯字符串(比如错误信息),那可以先改用ResponseBody接收,手动处理响应内容:
Call<ResponseBody> call = apiService.getUserData(); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (response.isSuccessful()) { try { String rawResponse = response.body().string(); // 先判断是不是有效JSON if (rawResponse.startsWith("{")) { // 转成User对象 User user = new Gson().fromJson(rawResponse, User.class); // 这里就可以把user的数据展示到页面上了 showUserInfo(user); } else { // 处理字符串类型的响应(比如错误提示) Toast.makeText(context, rawResponse, Toast.LENGTH_SHORT).show(); } } catch (IOException e) { e.printStackTrace(); } } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { t.printStackTrace(); } });
最后验证一下
修复完服务器和代码后,再用Postman请求一次,确保返回的是干净的JSON对象,没有多余字符,然后运行App,应该就能正常解析并展示用户数据了。
内容的提问来源于stack exchange,提问作者Amir
相关产品推荐
相关产品推荐

