Android报错java.lang.IllegalStateException: 无法读取已转换响应体的原始内容
问题:Retrofit同步数据时崩溃,报错
java.lang.IllegalStateException: Cannot read raw response body of a converted body 在使用Retrofit将数据同步到服务器时,应用持续崩溃,报错信息如上。相关代码和Logcat日志如下:
出错代码
private void uploadToServer(String date, String userid, JSONArray attachment, String expense, String ad_user, String ad_pass, String versionCode, String apiVersion, String dcrSync, String urlParameters) { RequestBody description = RequestBody.create(MediaType.parse("text/plain"), attachment.toString()); APIinterface apIinterface = RetrofitClient.getRetrofitClient(getApplicationContext()).create(APIinterface.class); final Call<ResponseBody> call = apIinterface.uploadExpenseData(Datafields.tag_url.get("expense_sync").toString(), date, userid, attachment.toString(), expense, ad_user, ad_pass, versionCode, apiVersion, dcrSync); Log.e("attachement", attachment.toString()); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { Log.e("syncObjetc", String.valueOf(response)); if (response.isSuccessful()) { ResponseBody responseBody = response.body(); String url = response.raw().request().url().toString(); ResponseBody body = response.raw().body(); try { Toast.makeText(Sync.this, responseBody.string(), Toast.LENGTH_SHORT).show(); Toast.makeText(Sync.this, body.string(), Toast.LENGTH_SHORT).show(); progressDialog.dismiss(); JSONObject jsonObject = new JSONObject(response.body().string()); JSONObject messageObj = jsonObject.getJSONObject("message"); JSONObject codeObject = jsonObject.getJSONObject("code"); JSONObject syncObjetc = jsonObject.getJSONObject("synchData"); String message = messageObj.getString("message"); int code = codeObject.getInt("code"); String date = syncObjetc.getString("date"); Log.e("String message ", message); Log.e("syncObjetc", String.valueOf(syncObjetc)); Log.e("resbody ", responseBody.string()); altDialog.setMessage(message); altDialog.setNegativeButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startActivity(new Intent(Sync.this, Sync.class)); overridePendingTransition(0, 0); } }); altDialog.show(); if (code == 0) { syncExpense(date); } } catch (JSONException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { progressDialog.dismiss(); Toast.makeText(Sync.this, "Sync Failed", Toast.LENGTH_LONG).show(); Log.e("Faliure", t.getMessage()); } }); }
Logcat日志
java.lang.IllegalStateException: Cannot read raw response body of a converted body. at retrofit2.OkHttpCall$NoContentResponseBody.source(OkHttpCall.java:274) at okhttp3.ResponseBody.string(ResponseBody.java:173) at com.anantfso.glenmark_fso_demo.Sync$19.onResponse(Sync.java:1898) at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1$1.run(DefaultCallAdapterFactory.java:83) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 2023-04-24 12:58:48.459 9893-9893/com.anantfso.glenmark_fso_demo W/System.err: java.lang.IllegalStateException: Cannot read raw response body of a converted body. 2023-04-24 12:58:48.459 9893-9893/com.anantfso.glenmark_fso_demo W/System.err: at retrofit2.OkHttpCall$NoContentResponseBody.source(OkHttpCall.java:274) 2023-04-24 12:58:48.459 9893-9893/com.anantfso.glenmark_fso_demo W/System.err: at okhttp3.ResponseBody.string(ResponseBody.java:173) 2023-04-24 12:58:48.459 9893-9893/com.anantfso.glenmark_fso_demo W/System.err: at com.anantfso.glenmark_fso_demo.Sync$19.onResponse(Sync.java:1898) 2023-04-24 12:58:48.460 9893-9893/com.anantfso.glenmark_fso_demo W/System.err: at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1$1.run(DefaultCallAdapterFactory.java:83) 2023-04-24 12:58:48.460 9893-9893/com.anantfso.glenmark_fso_demo W/System.err: at android.os.Handler.handleCallback(Handler.java:883) 2023-04-24 12:58:48.460 9893-9893/com.anantfso.glenmark_fso_demo W/System.err: at android.os.Handler.dispatchMessage(Handler.java:100) 2023-04-24 12:58:48.460 9893-9893/com.anantfso.glenmark_fso_demo W/System.err: at android.os.Looper.loop(Looper.java:214) 2023-04-24 12:58:48.460 9893-9893/com.anantfso.glenmark_fso_demo W/System.err: at android.app.ActivityThread.main(ActivityThread.java:7356) 2023-04-24 12:58:48.460 9893-9893/com.anantfso.glenmark_fso_demo W/System.err: at java.lang.reflect.Method.invoke(Native Method) 2023-04-24 12:58:48.460 9893-9893/com.anantfso.glenmark_fso_demo W/System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 2023-04-24 12:58:48.460 9893-9893/com.anantfso.glenmark_fso_demo W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
崩溃原因
- Retrofit中,调用
response.body()获取转换后的响应体时,原始响应体(response.raw().body())已被Retrofit处理并关闭,无法再次读取,强行读取就会触发该异常 ResponseBody.string()方法会一次性消耗响应体的输入流,第二次调用时流已关闭,同样会抛出异常。代码中多次调用responseBody.string()、response.body().string(),导致重复消耗流- 同时混用
response.body()和response.raw().body(),既读取转换后的响应体,又尝试读取已被处理的原始响应体,触发了Retrofit的保护机制
解决方法
核心思路
只读取一次响应体内容并缓存,后续所有操作都使用缓存的字符串,同时不要调用response.raw().body()。
修改后的代码
private void uploadToServer(String date, String userid, JSONArray attachment, String expense, String ad_user, String ad_pass, String versionCode, String apiVersion, String dcrSync, String urlParameters) { RequestBody description = RequestBody.create(MediaType.parse("text/plain"), attachment.toString()); APIinterface apIinterface = RetrofitClient.getRetrofitClient(getApplicationContext()).create(APIinterface.class); final Call<ResponseBody> call = apIinterface.uploadExpenseData(Datafields.tag_url.get("expense_sync").toString(), date, userid, attachment.toString(), expense, ad_user, ad_pass, versionCode, apiVersion, dcrSync); Log.e("attachement", attachment.toString()); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { Log.e("syncObjetc", String.valueOf(response)); if (response.isSuccessful()) { ResponseBody responseBody = response.body(); String url = response.raw().request().url().toString(); // 只读取一次响应体内容并缓存 String responseContent = ""; try { if (responseBody != null) { responseContent = responseBody.string(); } Toast.makeText(Sync.this, responseContent, Toast.LENGTH_SHORT).show(); progressDialog.dismiss(); JSONObject jsonObject = new JSONObject(responseContent); JSONObject messageObj = jsonObject.getJSONObject("message"); JSONObject codeObject = jsonObject.getJSONObject("code"); JSONObject syncObjetc = jsonObject.getJSONObject("synchData"); String message = messageObj.getString("message"); int code = codeObject.getInt("code"); String syncDate = syncObjetc.getString("date"); Log.e("String message ", message); Log.e("syncObjetc", String.valueOf(syncObjetc)); Log.e("resbody ", responseContent); altDialog.setMessage(message); altDialog.setNegativeButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startActivity(new Intent(Sync.this, Sync.class)); overridePendingTransition(0, 0); } }); altDialog.show(); if (code == 0) { syncExpense(syncDate); } } catch (JSONException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { progressDialog.dismiss(); Toast.makeText(Sync.this, "Sync Failed", Toast.LENGTH_LONG).show(); Log.e("Failure", t.getMessage()); } }); }
关键修改点
- 新增
responseContent变量,一次性读取响应体内容,后续所有操作都使用这个变量 - 移除了对
response.raw().body()的调用和读取 - 把所有原本调用
ResponseBody.string()的地方替换为使用responseContent - 变量名
date重命名为syncDate,避免和方法参数的date冲突
内容的提问来源于stack exchange,提问作者Abm
相关产品推荐
相关产品推荐

