Android Retrofit 2.1.0调用API遇404,Response.body()返回空
看起来你遇到的核心问题是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

