为何Retrofit登录响应正常,转JSONObject却报End of input异常
核心原因
org.json.JSONException: End of input at character 0的报错,本质是传入JSONObject构造方法的字符串是空值,空值的来源是Retrofit封装的ResponseBody是一次性消费的流对象,不可重复读取。
ResponseBody内部承载的是网络响应的输入流,每调用一次.string()方法,就会把流内所有数据全部读取完毕,同时关闭流;后续再次调用同一个ResponseBody实例的.string()方法时,流已经没有任何剩余数据,只会返回空字符串。- 代码里第一次调用
response.body().string()打印日志的时候,已经把整段JSON响应体读完了;第二次再调用同个实例的.string()创建JSONObject时,拿到的已经是空串,自然无法完成解析。
修复方案
只要保证响应体的字符串只读取一次,后续日志、JSON解析操作都基于这次读取得到的本地字符串变量处理,绝对不要重复调用.string(),就能解决这个问题。
修正后的代码示例:
apiInterface.Login(Email, Pass).enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (response.isSuccessful()) { try { // 仅做一次流读取,结果存入本地变量 String responseContent = response.body().string(); Log.d("PONSEMONSE", responseContent); // 直接用本地变量做解析,不要重复读取响应体 JSONObject jsonObject = new JSONObject(responseContent); Log.d("LONO", jsonObject.getString("access_token")); } catch (IOException | JSONException e) { e.printStackTrace(); } } } });
优化提示
- 如果不需要手动处理原始响应字节流,可以直接在Retrofit接口定义里把回调泛型设为对应的Java Bean类,搭配官方的Converter转换器完成自动JSON解析,完全省去手动读流、手动转JSONObject的步骤,从根源上避免重复读流的问题。
- 涉及大文件下载、边下边存的场景如果需要多次读取流内容,可以用
response.peekBody(long byteCount)方法创建一个可以重复读取的临时响应体,当前普通接口请求的场景完全不需要引入额外操作,单次读取存变量就是最轻量的实现。
内容的提问来源于stack exchange,提问作者moumenShobakey
相关产品推荐
相关产品推荐

