Android Retrofit2认证开发中response.body().string()为空问题排查
问题分析与解决方案
你的问题核心是Retrofit配置与服务器响应格式不匹配,导致response.body()为空,即使服务器确实返回了"SUCCESS"。以下是具体原因和修复步骤:
核心原因
- Gson转换器无法处理纯文本响应:你在Retrofit中添加了
GsonConverterFactory,但服务器返回的是纯文本"SUCCESS"而非标准JSON格式。Gson会尝试将纯文本解析为JSON对象,解析失败后返回null的body。 - 未检查响应状态码:你直接读取
response.body(),但如果服务器返回非200-300的状态码(比如用户已存在时返回409),response.body()会为null,此时应该读取response.errorBody()。 - ResponseBody.string()的流特性:流只能读取一次,若后续需要复用响应内容,必须先转为字符串保存。
修复方案(二选一)
方案一:添加字符串转换器处理纯文本响应
适合服务器确实返回纯文本的场景:
- 添加Scalars转换器依赖:在app模块的
build.gradle中添加:
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
- 修改RetrofitClient配置:将
ScalarsConverterFactory放在Gson转换器之前:
private RetrofitClient () { retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build(); }
- 修改API接口返回类型:将
Call<ResponseBody>改为Call<String>:
public interface API { @POST("register") // 替换为实际接口路径 Call<String> createUser(@Body User user); }
- 更新RegisterActivity回调逻辑:添加状态码检查:
call.enqueue(new Callback<String>() { @Override public void onResponse(Call<String> call, Response<String> response) { if (response.isSuccessful()) { String s = response.body(); if ("SUCCESS".equals(s)) { Toast.makeText(RegisterActivity.this, "Successfully registered. Please login", Toast.LENGTH_LONG).show(); startActivity(new Intent(RegisterActivity.this, LoginActivity.class)); } else { Toast.makeText(RegisterActivity.this, "User already exists!", Toast.LENGTH_LONG).show(); } } else { try { String errorMsg = response.errorBody().string(); Toast.makeText(RegisterActivity.this, errorMsg, Toast.LENGTH_LONG).show(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(RegisterActivity.this, "Request failed", Toast.LENGTH_LONG).show(); } } } @Override public void onFailure(Call<String> call, Throwable t) { Toast.makeText(RegisterActivity.this, t.getMessage(), Toast.LENGTH_LONG).show(); } });
方案二:修改服务器返回JSON格式(推荐)
更符合RESTful规范,便于后续扩展:
服务器返回标准JSON:比如注册成功返回
{"status":"SUCCESS"},用户已存在返回{"status":"EXISTS"}。创建响应实体类:
public class ApiResponse { private String status; public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } }
- 修改API接口返回类型:
public interface API { @POST("register") Call<ApiResponse> createUser(@Body User user); }
- 更新回调逻辑:
call.enqueue(new Callback<ApiResponse>() { @Override public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) { if (response.isSuccessful()) { ApiResponse apiResponse = response.body(); if (apiResponse != null && "SUCCESS".equals(apiResponse.getStatus())) { Toast.makeText(RegisterActivity.this, "Successfully registered. Please login", Toast.LENGTH_LONG).show(); startActivity(new Intent(RegisterActivity.this, LoginActivity.class)); } else { Toast.makeText(RegisterActivity.this, "User already exists!", Toast.LENGTH_LONG).show(); } } else { try { String errorMsg = response.errorBody().string(); Toast.makeText(RegisterActivity.this, errorMsg, Toast.LENGTH_LONG).show(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(RegisterActivity.this, "Request failed", Toast.LENGTH_LONG).show(); } } } @Override public void onFailure(Call<ApiResponse> call, Throwable t) { Toast.makeText(RegisterActivity.this, t.getMessage(), Toast.LENGTH_LONG).show(); } });
额外调试建议
- 在回调中打印
response.code()和response.message(),确认服务器返回的状态码是否符合预期。 - 用Postman或curl直接调用服务器接口,验证返回内容和Content-Type是否正确。
内容的提问来源于stack exchange,提问作者EloneTheBeige
相关产品推荐
相关产品推荐

