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

Android Retrofit 2.1.0调用API遇404,Response.body()返回空

解决Retrofit调用API返回404且Response.body()为null的问题

看起来你遇到的核心问题是404状态码——这说明服务器找不到你请求的资源,咱们先从最关键的URL配置入手,再一步步排查其他潜在问题:

1. 修正Retrofit接口的请求路径(解决404的核心)

你的ApiUtils里已经把BASE_URL设为http://demo.museum.vebrary.vn/api/,但SOService中的@GET("/stuff/getall")多了一个开头的斜杠。这会让Retrofit拼接出的URL变成http://demo.museum.vebrary.vn/api//stuff/getall(两个连续斜杠),服务器根本识别不了这个路径,直接返回404。

把Service接口改成这样:

public interface SOService {
    // 去掉开头的斜杠,让路径和BASE_URL正确拼接
    @GET("stuff/getall")
    Call<SOAnswersResponse> getAnswers();
}

2. 加个日志拦截器,看清实际请求的全貌

为了确认请求是否符合预期,建议给Retrofit加上OkHttp的日志拦截器,这样能在Logcat里看到完整的请求URL、请求头、响应内容,排查问题更直观。

首先在build.gradle里添加依赖(如果还没加):

implementation 'com.squareup.okhttp3:logging-interceptor:4.11.0'

然后修改RetrofitClient类,把日志拦截器加进去:

public class RetrofitClient {
    private static Retrofit retrofit = null;

    public static Retrofit getClient(String baseUrl) {
        if (retrofit == null) {
            // 配置日志拦截器,打印完整的请求响应信息
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
            
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .addInterceptor(logging)
                    .build();

            retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .client(okHttpClient)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

3. 别直接拿Response.body()!先判断响应是否成功

即使URL改对了,也不能直接调用response.body()——当响应状态码不是2xx(比如404、500)时,body()会返回null。你需要先判断请求是否成功,再处理结果,同时也要处理网络失败的情况。

把你主Activity里没写完的API调用部分补全:

@Override
protected void onCreate (Bundle savedInstanceState) {
    super.onCreate( savedInstanceState );
    setContentView(R.layout.test );
    mService = ApiUtils.getSOService();
    mRecyclerView = (RecyclerView) findViewById(R.id.rcvCategogyNameMenuTest);
    mAdapter = new CategogyNameRecyclerViewAdapter(this, new ArrayList<StuffModel>(0), new CategogyNameRecyclerViewAdapter.PostItemListener() {
        @Override
        public void onPostClick(long id) {
            Toast.makeText(Testttt.this, "Post id is" + id, Toast.LENGTH_SHORT).show();
        }
    });
    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
    mRecyclerView.setLayoutManager(layoutManager);
    mRecyclerView.setAdapter(mAdapter);
    mRecyclerView.setHasFixedSize(true);
    // 调用API获取数据
    fetchStuffData();
}

private void fetchStuffData() {
    mService.getAnswers().enqueue(new Callback<SOAnswersResponse>() {
        @Override
        public void onResponse(Call<SOAnswersResponse> call, Response<SOAnswersResponse> response) {
            if (response.isSuccessful()) {
                // 请求成功,更新RecyclerView
                SOAnswersResponse answerResponse = response.body();
                if (answerResponse != null && answerResponse.getStuffModels() != null) {
                    mAdapter.updateAnswers(answerResponse.getStuffModels());
                } else {
                    Toast.makeText(Testttt.this, "未获取到有效数据", Toast.LENGTH_SHORT).show();
                }
            } else {
                // 请求失败,打印错误信息
                Toast.makeText(Testttt.this, "请求失败,状态码:" + response.code(), Toast.LENGTH_SHORT).show();
                // 可以获取错误响应的具体内容
                try {
                    String errorContent = response.errorBody().string();
                    Log.e("API_ERROR", "错误详情:" + errorContent);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onFailure(Call<SOAnswersResponse> call, Throwable t) {
            // 网络异常(比如无网、超时)
            Toast.makeText(Testttt.this, "网络请求失败:" + t.getMessage(), Toast.LENGTH_SHORT).show();
            t.printStackTrace();
        }
    });
}

4. 检查模型类的getter方法是否齐全

你的StuffModel类里已经用@SerializedName注解匹配了JSON字段,但我注意到你没写getter方法——适配器里需要调用item.getSTUFFNAME()来显示数据,所以必须补上这些方法:

public class StuffModel {
    @SerializedName("STUFFID")
    @Expose
    private Integer sTUFFID;
    @SerializedName("STUFFCODE")
    @Expose
    private String sTUFFCODE;
    @SerializedName("STUFFNAME")
    @Expose
    private String sTUFFNAME;
    @SerializedName("STUFFNOTE")
    @Expose
    private String sTUFFNOTE;
    @SerializedName("STUFFORDER")
    @Expose
    private Integer sTUFFORDER;
    @SerializedName("CUSTOMERID")
    @Expose
    private String cUSTOMERID;
    @SerializedName("EXHIBITS")
    @Expose
    private List<Object> eXHIBITS = null;

    // 补充所有字段的getter方法
    public Integer getSTUFFID() {
        return sTUFFID;
    }

    public String getSTUFFCODE() {
        return sTUFFCODE;
    }

    public String getSTUFFNAME() {
        return sTUFFNAME;
    }

    public String getSTUFFNOTE() {
        return sTUFFNOTE;
    }

    public Integer getSTUFFORDER() {
        return sTUFFORDER;
    }

    public String getCUSTOMERID() {
        return cUSTOMERID;
    }

    public List<Object> getEXHIBITS() {
        return eXHIBITS;
    }
}

按照上面的步骤调整后,应该能解决404的问题,成功获取数据并展示到RecyclerView里。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:50:09