You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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;

    }

错误原因分析

  1. RequestBody媒体类型错误:所有表单字段都指定multipart/form-data类型,但Multipart请求中普通字段无需手动指定该类型,错误设置会导致请求格式异常;图片文件未使用对应MIME类型(如image/jpeg),服务器无法正确识别文件内容,返回异常响应。
  2. 响应解析不匹配:服务器返回的响应可能包含非JSON内容(如调试信息、HTML冗余字符),Gson转换器无法完全消耗响应体,触发错误。
  3. 文件路径适配问题: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 01:42:03