使用Retrofit发送Multipart图片时遇Json Data未完全消费错误
Retrofit Multipart上传图片报错「Json Data Was not fully consumed」排查与解决
问题背景
使用Retrofit以Multipart形式发送图片时,出现「Json Data Was not fully consumed」错误,Postman测试API正常,但代码实现报错,已尝试Stack Overflow方案无效。
相关代码
ApiHandler类
public class ApiHandler { private static final String BASE_URL = "https://aaplasevak.com/"; private static Retrofit retrofit; public static Retrofit getRetrofitInstance() { if(retrofit == null){ OkHttpClient client = new OkHttpClient.Builder().build(); Gson gson = new GsonBuilder().setLenient().create(); retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .client(client) .addConverterFactory(GsonConverterFactory.create(gson)) .build(); } return retrofit; } }
Api Interface类
@Multipart @POST("whatsapp_api.php") Call<WhatsAppApiResponseData> sentWhatsAppMessage( @Part("series_id") RequestBody seriesId, @Part("colony_id") RequestBody colonyId, @Part("row_id") RequestBody rowId, @Part("watersupply_id") RequestBody waterSupplyId, @Part("constituency") RequestBody constituency, @Part("city_village") RequestBody cityVillage, @Part("zone") RequestBody zone, @Part("prabhag_ward") RequestBody prabhagWard, @Part("template_desc") RequestBody templateDesc, @Part MultipartBody.Part file );
API实现代码
private void sentWhatsAppMessage() { ApiInterface apiInterface = getRetrofitInstance().create(ApiInterface.class); RequestBody seriesId = RequestBody.create(MediaType.parse("multipart/form-data"), String.valueOf(spinner_series.getSelectedItemPosition())); RequestBody colonyId = RequestBody.create(MediaType.parse("multipart/form-data"), String.valueOf(spinner_colony.getSelectedItemPosition() + 1)); RequestBody rowId = RequestBody.create(MediaType.parse("multipart/form-data"), String.valueOf(spinner_row.getSelectedItemPosition() + 1)); RequestBody waterSupplyId = RequestBody.create(MediaType.parse("multipart/form-data"), String.valueOf(spinner_water_Supply.getSelectedItemPosition())); RequestBody zoneId = RequestBody.create(MediaType.parse("multipart/form-data"), String.valueOf(spinner_zone.getSelectedItemPosition())); RequestBody wardId = RequestBody.create(MediaType.parse("multipart/form-data"), String.valueOf(spinner_ward.getSelectedItemPosition())); RequestBody constituencyId = RequestBody.create(MediaType.parse("multipart/form-data"), String.valueOf(spinner_constituency.getSelectedItemPosition())); RequestBody cityVillageId = RequestBody.create(MediaType.parse("multipart/form-data"), String.valueOf(spinner_city_village.getSelectedItemPosition())); RequestBody message = RequestBody.create(MediaType.parse("multipart/form-data"), etMessage.getText().toString()); File file = new File(getRealPathFromURI(selectedUri)); RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile); Call<WhatsAppApiResponseData> call = apiInterface.sentWhatsAppMessage(seriesId,colonyId,rowId,waterSupplyId,constituencyId,cityVillageId,zoneId,wardId,message,body); //Log.d("Api Response", "WhatsApp: " + whatsAppApiBody.toString()); call.enqueue(new Callback<WhatsAppApiResponseData>() { @Override public void onResponse(Call<WhatsAppApiResponseData> call, retrofit2.Response<WhatsAppApiResponseData> response) { if (response.isSuccessful()) { WhatsAppApiResponseData responseData = response.body(); String status = responseData.toString(); Toast.makeText(WhatsappActivity.this, "Success!! " + status, Toast.LENGTH_SHORT).show(); Log.d("Api Response","data: " + status); finish(); } else { Toast.makeText(WhatsappActivity.this, "Response Error..!!", Toast.LENGTH_SHORT).show(); Log.e("Api Response", "Response Error.."); } } @Override public void onFailure(Call<WhatsAppApiResponseData> call, Throwable throwable) { Log.e("Api Response", "Error.." + throwable.getLocalizedMessage()); Toast.makeText(WhatsappActivity.this, "Error.." + throwable.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); throwable.printStackTrace(); } }); }
getRealPathFromUri方法
private String getRealPathFromURI(Uri contentUri) { String[] projection = {MediaStore.Images.Media.DATA}; Cursor cursor = getContentResolver().query(contentUri, projection, null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); String filePath = cursor.getString(column_index); cursor.close(); return filePath; }
错误原因分析
- RequestBody媒体类型错误:所有表单字段都指定
multipart/form-data类型,但Multipart请求中普通字段无需手动指定该类型,错误设置会导致请求格式异常;图片文件未使用对应MIME类型(如image/jpeg),服务器无法正确识别文件内容,返回异常响应。 - 响应解析不匹配:服务器返回的响应可能包含非JSON内容(如调试信息、HTML冗余字符),Gson转换器无法完全消耗响应体,触发错误。
- 文件路径适配问题:
getRealPathFromURI方法在Android 10及以上系统无法正确获取文件真实路径,导致文件读取异常,间接引发响应解析错误。
解决办法
1. 修正RequestBody媒体类型
- 普通表单字段使用
text/plain类型,或不指定MediaType(Retrofit会自动处理);图片文件使用对应MIME类型:
// 普通字段示例 RequestBody seriesId = RequestBody.create(MediaType.parse("text/plain"), String.valueOf(spinner_series.getSelectedItemPosition())); // 文件字段示例:自动获取图片MIME类型 String mimeType = getContentResolver().getType(selectedUri); RequestBody requestFile = RequestBody.create(MediaType.parse(mimeType), file); MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
2. 排查服务器响应内容
- 在
onResponse中打印错误响应体,确认是否存在非JSON内容:
@Override public void onResponse(Call<WhatsAppApiResponseData> call, retrofit2.Response<WhatsAppApiResponseData> response) { if (!response.isSuccessful()) { try { String errorBody = response.errorBody().string(); Log.e("Api Response", "Error Body: " + errorBody); } catch (IOException e) { e.printStackTrace(); } } }
- 若响应存在冗余内容,需要求后端修正响应格式为纯JSON,或自定义ConverterFactory过滤多余字符。
3. 优化Gson解析配置
- 放宽Gson解析规则,忽略未知字段和格式不严谨问题:
Gson gson = new GsonBuilder() .setLenient() .ignoreUnknownFields() .create();
4. 适配Android 10+文件读取
- 替换
getRealPathFromURI方法,改用ContentResolver读取文件流:
private RequestBody getFileRequestBody(Uri uri) throws IOException { InputStream inputStream = getContentResolver().openInputStream(uri); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, length); } byte[] fileBytes = outputStream.toByteArray(); inputStream.close(); outputStream.close(); return RequestBody.create(MediaType.parse(getContentResolver().getType(uri)), fileBytes); }
内容的提问来源于stack exchange,提问作者Mamta
相关产品推荐
相关产品推荐

