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

解决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);
}
额外优化建议
  1. 密码安全:API直接返回明文密码存在风险,建议登录验证成功后返回认证Token,而非密码
  2. Android端空值处理:在onResponse方法中添加response.body() == null的判断,避免空指针异常
  3. API错误反馈:当无匹配用户时,返回NotFound()而非Ok(null),Android端可通过response.code()判断登录失败原因

内容的提问来源于stack exchange,提问作者user21834984

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 10:15:08