解决Android登录对接Web API的Expected BEGIN_OBJECT解析错误
问题描述
对接Web API的Android项目中,登录功能运行时抛出错误:java.lang.illegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
核心原因:API返回JSON数组格式(如[{"UserID":1.0,"username":"Steady","password":"test"}]),但Android端Retrofit接口期望解析为单个LoginResponse对象,数据格式不匹配导致解析失败。
解决方案
一、修改Web API代码,返回单个对象而非数组
登录场景下,账号密码匹配的用户应唯一,直接返回单个Person对象即可:
[HttpGet] public IHttpActionResult getUser(string userName, string passWord) { Person api = null; SqlConnection mainconn = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString); // 添加TOP 1确保只返回一条匹配数据 SqlCommand da = new SqlCommand("Select TOP 1 UserID, username, password from tblLogin where username = @username and password = @password", mainconn); try { mainconn.Open(); da.Parameters.Add("@username", SqlDbType.VarChar); da.Parameters["@username"].Value = userName.ToString(); da.Parameters.Add("@password", SqlDbType.VarChar); da.Parameters["@password"].Value = passWord.ToString(); SqlDataReader dr = da.ExecuteReader(); // 用if代替while,仅读取第一条匹配数据 if(dr.Read()) { api = new Person() { UserID = Convert.ToDecimal(dr.GetValue(0)), username = Convert.ToString(dr.GetValue(1)), password = Convert.ToString(dr.GetValue(2)) }; } } catch(Exception ex) { // 处理数据库连接或查询异常 return InternalServerError(ex); } finally { mainconn.Close(); // 确保关闭数据库连接,避免资源泄漏 } return Ok(api); }
关键修改点:
- 将返回类型从
List<Person>改为单个Person对象 - SQL语句添加
TOP 1,限制仅返回一条匹配数据 - 用
if(dr.Read())替代while循环,读取第一条数据后终止 - 新增try-catch-finally块处理异常并确保连接关闭
- 优化查询条件为精确匹配(
username = @username),避免部分匹配导致的错误
修改后API返回格式变为单个JSON对象:
{"UserID":1.0,"username":"Steady","password":"test"}
二、同步调整Android端LoginResponse模型类
移除无用字段,确保模型与API返回的字段完全对应:
public class LoginResponse implements Serializable { private String UserID; private String username; private String password; // 新增password字段,匹配API返回 public String getUserID() { return UserID; } public void setUserID(String userID) { UserID = userID; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
关键调整:
- 删除多余的
loginRequests字段 - 新增
password字段,与API返回的字段保持一致 - 确保字段大小写与API返回严格匹配(Gson默认按大小写匹配字段)
三、验证Retrofit接口
UserService接口无需修改,保持原有定义即可,现在API返回的单个对象可被正常解析:
public interface UserService { @GET("api/user/") Call<LoginResponse> loginUser(@Query("username") String username, @Query("password") String password); }
额外优化建议
- 密码安全:API直接返回明文密码存在风险,建议登录验证成功后返回认证Token,而非密码
- Android端空值处理:在
onResponse方法中添加response.body() == null的判断,避免空指针异常 - API错误反馈:当无匹配用户时,返回
NotFound()而非Ok(null),Android端可通过response.code()判断登录失败原因
内容的提问来源于stack exchange,提问作者user21834984
相关产品推荐
相关产品推荐

