2017-06-30 47 views
6

Próbuję wykonać żądanie wielostronicowego POST za pomocą Retrofit2, gdzie przesyłam do interfejsu API niestandardowy plik.Retrofit. wyjątek java.net.ProtocolException: oczekiwany * bajtów, ale odebrano *

losowo zawiedzie on z tego wyjątku:

W/System.err: java.net.ProtocolException: expected 154 bytes but received 634 

Czy ktoś mógłby umieścić trochę światła na to?

To jest mój kod w interfejsie:

@Multipart 
@POST("recordings/{id}/{rec_id}/") 
Call<ResponseBody> uploadRecording(@Path("id") String id, @Path("rec_id") String rec_id, @Part MultipartBody.Part bleFile); 

W konstruktorze:

public ApiConnectionManager(Context con){ 
    Gson gson = new GsonBuilder() 
      .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") 
      .create(); 

    OkHttpClient.Builder client = new OkHttpClient.Builder(); 
    HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); 
    loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 
    client.addInterceptor(loggingInterceptor); 

    Retrofit retrofit = new Retrofit.Builder() 
      .baseUrl(con.getResources().getString(R.string.api_url)) // API url is hidden 
      .addConverterFactory(GsonConverterFactory.create(gson)) 
      .client(client.build()) 
      .build(); 

    this.companyAPI = retrofit.create(CompanyAPI.class); 
} 

iw sposobie Dodano:

private void uploadFile(String id, final File bleFile) { 
    MediaType MEDIA_TYPE = MediaType.parse("multipart/mixed"); 
    RequestBody requestBody = RequestBody.create(MEDIA_TYPE,bleFile); 
    MultipartBody.Part partFile = MultipartBody.Part.createFormData("file", bleFile.getName(), requestBody); 
    String recordingId = bleFile.getName().replace(".BLE",""); 
    Call<ResponseBody> call = companyAPI.uploadRecording(id, recordingId, partFile); 
    call.enqueue(new Callback<ResponseBody>() { 
     @Override 
     public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { 
      Log.d(TAG+"-Upload "+bleFile.getName(),response.message()); 
     } 

     @Override 
     public void onFailure(Call<ResponseBody> call, Throwable t) { 
      Log.d(TAG,"FAILED"); 
      t.printStackTrace(); 
     } 
    }); 
} 

Odpowiedz

1

Po krótkim przestudiowaniu problemu zdałem sobie sprawę, że zawartość pliku zawsze się zmienia (ponieważ jest to sygnał wyjściowy czujnika).

Oznacza to, że plik sprawdzany dla HEAD i pliku dla BODY może nie zawierać tych samych danych (stąd różnej długości), co spowodowało niezgodność.

Rozwiązałem ten plik creating a copy i wysłałem go (kopię) zamiast oryginalnego pliku.

1

Oto co mogę użyć dla wszystkich moje prośby i nie mam żadnych problemów. Daj mi znać, jeśli to nie działa. Zakładam, że nazwa POST dla twojego pliku to "plik".

W protokole:

@Multipart 
@POST 
Call<ResponseBody> request(
     @Url String url, // Request URL 
     @PartMap Map<String, String> vars, // POST Strings 
     @PartMap Map<String, RequestBody> files // POST Files 
); 

skonstruować połączenia:

Map<String, String> vars = new HashMap<>(); 
Map<String, RequestBody> files = new HashMap<>(); 

/** Put a string **/ 

vars.put("name", "value"); 

/** Put a file **/ 

String key = String.format(Locale.US, "file\"; filename=\"%s", file.getName()); 
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); 
files.put(key, requestBody); 

/** Construct the call **/ 

Call<ResponseBody> call = mProtocol.request(url, vars, files); 

call.enqueue(new Callback<ResponseBody>() { 
     @Override 
     public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { 
      Log.d("Debug", response.body().string()); 
     } 

     @Override 
     public void onFailure(Call<ResponseBody> call, Throwable t) { 
      if (call.isCanceled()) Log.d("Debug", "Call Canceled"); 
      else Log.d("Debug", "Call Failed: " + t.toString()); 
     } 
}); 

PS: Można użyć tego fragmentu kodu na przesyłanie wielu plików, ponieważ przyjmuje mapę plików, a nie pojedynczy plik.

PS # 2: Z powodu kilku problemów, które miałem z tą metodą, musiałem dodać poniższy kod, aby upewnić się, że nigdy nie wyśle ​​pustej lub pustej mapy.

if (vars == null) { 
    vars = new HashMap<>(); 
    vars.put("01110011", "01101101"); // put whatever you want 
} 
if (files == null) files = new HashMap<>(); 
+0

użycie adnotacji "@PartMap" zamiast "@Part" rozwiązało problem. – kike

+0

Mógłbyś proszę dodać call.enqueue() do tej odpowiedzi, aby osoby z tym samym problemem mogły mieć działający fragment kodu? – kike

+1

@kike Zmieniłem swoją odpowiedź, a także dodałem sposób wysyłania ciągów poza plikami. –

2

Stawiałem czoła temu problemowi, gdy próbowałem załadować nagranie. Rozwiązałem go, zatrzymując proces nagrywania przed wywołaniem usługi internetowej, aby przesłać plik.

objMediaRecorder.stop(); 
objMediaRecorder.release(); 
objMediaRecorder = null;