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

Android用Retrofit2+OkHttp3请求Laravel接口返回空JSONObject问题

问题分析与解决方案

先梳理下你代码里的两个核心问题,这正是导致响应体为空的关键原因:

1. OkHttp拦截器未继续执行请求

你的Interceptor实现漏掉了最关键的一步——没有返回chain.proceed(request),这会导致请求被拦截后无法发送到服务器,虽然日志显示200状态码,但实际上可能是无效的缓存或空响应。

修复方式:在Interceptor的intercept方法末尾添加返回语句:

httpClient.addInterceptor(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        Request request = original.newBuilder()
            .header("Accept", "application/json")
            .header("Content-Type", "application/json")
            .header("Authorization", "Bearer " + token)
            .build();
        // 必须添加这行,让请求继续流向服务器
        return chain.proceed(request);
    }
});

2. Gson无法正确解析JSONObject类型

Retrofit的GsonConverterFactory默认会将JSON数据解析为对应Java实体类,而非org.json.JSONObject。当你用Call<JSONObject>作为返回类型时,Gson无法正确映射JSON结构,最终得到空的JSONObject实例。

解决这个问题有两种推荐方案:

方案一:使用ResponseBody手动解析

修改接口定义返回ResponseBody,在回调中手动转换为JSONObject:

// SvcApi接口修改
@GET("api/me")
public Call<ResponseBody> getMe(@Query("device_id") String device_id);

然后在Activity的回调中处理:

Call<ResponseBody> call = svcAth.getMe(Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID));
call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        if (response.isSuccessful()) {
            try {
                // 读取响应字符串并手动解析为JSONObject
                String responseContent = response.body().string();
                JSONObject user = new JSONObject(responseContent);
                Log.e("完整响应体", user.toString());
                // 在这里处理用户数据
            } catch (IOException | JSONException e) {
                e.printStackTrace();
            }
        } else {
            // 处理错误情况
        }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        t.printStackTrace();
    }
});

方案二:创建实体类接收数据(推荐)

根据Laravel/api/me接口返回的JSON结构,创建对应的Java实体类,让Gson自动映射数据,这更符合Retrofit的设计理念,也更易维护。

比如假设你的接口返回如下JSON:

{
  "id": 1,
  "name": "Alberto",
  "email": "alberto@example.com",
  "created_at": "2018-05-19T21:48:22Z"
}

创建User类:

public class User {
    private int id;
    private String name;
    private String email;
    @SerializedName("created_at") // 对应JSON中的下划线字段
    private String createdAt;

    // 生成getter和setter方法
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public String getCreatedAt() { return createdAt; }
    public void setCreatedAt(String createdAt) { this.createdAt = createdAt; }
}

修改接口定义:

@GET("api/me")
public Call<User> getMe(@Query("device_id") String device_id);

在回调中直接使用实体类:

Call<User> call = svcAth.getMe(Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID));
call.enqueue(new Callback<User>() {
    @Override
    public void onResponse(Call<User> call, Response<User> response) {
        if (response.isSuccessful()) {
            User user = response.body();
            if (user != null) {
                Log.e("用户名", user.getName());
                Log.e("邮箱", user.getEmail());
                // 处理用户数据
            }
        }
    }

    @Override
    public void onFailure(Call<User> call, Throwable t) {
        t.printStackTrace();
    }
});

额外调试建议

添加OkHttp日志拦截器,查看完整的请求和响应内容,确认服务器是否真的返回了数据:

  1. 在build.gradle中添加依赖:
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.9'
  1. 初始化OkHttpClient时添加日志拦截器:
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
// 设置日志级别为BODY,会打印请求和响应的完整内容
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addInterceptor(loggingInterceptor);

这样你就能在LogCat中看到服务器返回的原始JSON数据,方便排查问题。

其他优化点

  • 移除StrictMode代码:在主线程执行数据库操作和Retrofit初始化不规范,容易导致ANR,建议将这些操作放到后台线程(比如AsyncTask或Coroutines)。
  • 将数据库操作(db.ExistsUser()和db.findUser())移到后台线程,避免阻塞主线程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:19:36