2015-11-02 17 views
5

Używam programu Square Retrofit w wersji 2.0 beta2. Próbowałem podążać za this tutorial . Próbuję przesłać obraz bitmapowy na serwer, ale jakoś kod nie działa. Próbowałem przetestować mój serwer za pomocą listonosza i mogę wysłać zdjęcie, a nawet je odzyskać. Oto mój kontroler kolby.Retrofit (2.0 beta2) Przesyłanie plików wieloskładnikowych nie działa

@app.route('/api/photo/user/<int:user_id>', methods=["POST"]) 
    def post_user_photo(user_id): 
     app.logger.info("post_user_photo=> user_id:{}, photo: {}".format(
      user_id, 
      request.files['photo'].filename, 
     )) 
     user = User.query.get_or_404(user_id) 
     try: 
      user.photo = request.files['photo'].read() 
     except Exception as e: 
      app.logger.exception(e) 
      db.session.rollback() 
      raise 
     db.session.commit() 
     return "", codes.no_content 

Użyłem listonosza do przetestowania kontrolera i tutaj jest żądanie wygenerowane przez listonosza.

POST /api/photo/user/5 HTTP/1.1 
Host: blooming-cliffs-9672.herokuapp.com 
Cache-Control: no-cache 
Postman-Token: 8117fb79-4781-449d-7d22-237c49b53389 
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW 

----WebKitFormBoundary7MA4YWxkTrZu0gW 
Content-Disposition: form-data; name="photo"; filename="sfsu.jpg" 
Content-Type: image/jpeg 


----WebKitFormBoundary7MA4YWxkTrZu0gW 

Mam zdefiniowaną usługę modernizacji i do przesłania obrazu, a tutaj jest mój kod Android. Interfejs część

@Multipart 
    @POST("/api/photo/user/{userId}") 
    Call<Void> uploadUserProfilePhoto(@Path("userId") Integer userId, @Part("photo") RequestBody photo); 

Oto część budowniczy klient

public static BeamItService getService(){ 
     if (service == null) { 
      OkHttpClient client = new OkHttpClient(); 
      HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); 
      interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 
      HttpLoggingInterceptor interceptor2 = new HttpLoggingInterceptor(); 
      interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS); 

      client.interceptors().add(interceptor); 
      client.interceptors().add(interceptor2); 

      service = new Retrofit.Builder() 
        .baseUrl(BASE_URL) 
        .client(client) 
        .addConverterFactory(GsonConverterFactory.create()) 
        .build().create(BeamItService.class); 
     } 
     return service; 
    } 

A oto kod Android aktywność, która próbuje załadować bitmapę.

private void uploadProfilePhoto(){ 
     BeamItService service = BeamItServiceTransport.getService(); 

     MediaType MEDIA_TYPE_PNG = MediaType.parse("image/jpeg"); 
     byte [] data = BitmapUtility.getBitmapToBytes(((BitmapDrawable) ivProfilePhoto.getDrawable()).getBitmap()); 
     Log.d(TAG, String.format("Profile detals => user_id: %d, size of data: %d", 5, data.length)); 

     RequestBody requestBody1 = RequestBody.create(MEDIA_TYPE_PNG, 
                data); 
     Log.d(TAG, "requestBody: " + requestBody1.toString()); 
     RequestBody requestBody2 = new MultipartBuilder() 
       .type(MultipartBuilder.FORM) 
       .addPart(Headers.of("Content-Disposition", "form-data; name=\"photo\"; filename=\"t.jpg\""), 
         requestBody1) 
       .build(); 
     Log.d(TAG, "requestBody: " + requestBody2.toString()); 
//  ProfileDetails profileDetails = new DBHelper(this).fetchProfileDetails(); 

     Call<Void> call = service.uploadUserProfilePhoto(5, requestBody2); 
     call.enqueue(new ProfilePhotoUploadCallback()); 
    } 

    private class ProfilePhotoUploadCallback implements Callback<Void> { 

     @Override 
     public void onResponse(Response<Void> response, Retrofit retrofit) { 
      Log.d(TAG, String.format("ProfilePhotoUploadCallback=> code: %d", response.code())); 
     } 

     @Override 
     public void onFailure(Throwable t) { 

     } 
    } 

Ale nie można go załadować, aplikacja kolby zwraca kod statusu 400 za każdym razem. Próbowałem umieścić punkt przerwania w aplikacji do kolb, ale prośba do niego nie dociera. oto log serwera

2015-11-02T06:05:42.288574+00:00 heroku[router]: at=info method=POST path="/api/photo/user/5" host=blooming-cliffs-9672.herokuapp.com request_id=2cc8b6c8-f12a-4e4b-8279-cedfc39712f2 fwd="204.28.113.240" dyno=web.1 connect=1ms service=88ms status=400 bytes=347 
2015-11-02T06:05:42.209347+00:00 app[web.1]: [2015-11-02 06:05:42 +0000] [11] [DEBUG] POST /api/photo/user/5 

Próbowałem też włączyć intercepter modernizacji i zalogować żądania i odpowiedzi, ale nie rozumiem całego ciała żądania POST. Oto dziennik Androida.

11-02 00:24:22.119 3904-4382/com.contactsharing.beamit D/OkHttp: --> POST /api/photo/user/5 HTTP/1.1 
11-02 00:24:22.119 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Type: multipart/form-data; boundary=4031e177-0e4b-4f16-abe8-20c54e506846 
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Length: 17171 
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Host: blooming-cliffs-9672.herokuapp.com 
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Connection: Keep-Alive 
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Accept-Encoding: gzip 
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: User-Agent: okhttp/2.6.0-SNAPSHOT 
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: --> END POST 
11-02 00:24:22.179 3904-4537/com.contactsharing.beamit I/DBHelper: Updated row: 1 
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: <-- HTTP/1.1 400 BAD REQUEST (195ms) 
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Connection: keep-alive 
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Server: gunicorn/19.3.0 
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Date: Mon, 02 Nov 2015 08:24:22 GMT 
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Type: text/html 
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Length: 192 
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Via: 1.1 vegur 
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: OkHttp-Selected-Protocol: http/1.1 
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: OkHttp-Sent-Millis: 1446452662120 
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: OkHttp-Received-Millis: 1446452662316 
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: <-- END HTTP 

Proszę o pomoc, utknąłem i nie jestem w stanie zrobić żadnego postępu.

Odpowiedz

11

Tu zagnieżdżasz treść żądania wieloczęściowego (wieloczęściowy w wieloczęściowym).

Wdrożono coś podobnego niedawno, zamiast używać @Multipart i @Part można użyć @Body z MultipartBuilder.

@POST("/api/photo/user/{userId}") 
Call<Void> uploadUserProfilePhoto(@Path("userId") Integer userId, @Body RequestBody photo); 

Wtedy zamiast korzystania MultipartBuilder.addPart(...) korzystanie MultipartBuilder.addFormDataPart(name, filename, requestBody)

private void uploadProfilePhoto() { 
    BeamItService service = BeamItServiceTransport.getService(); 

    MediaType MEDIA_TYPE_PNG = MediaType.parse("image/jpeg"); 
    byte [] data = BitmapUtility.getBitmapToBytes(((BitmapDrawable) ivProfilePhoto.getDrawable()).getBitmap()); 
    Log.d(TAG, String.format("Profile detals => user_id: %d, size of data: %d", 5, data.length)); 

    RequestBody requestBody1 = RequestBody.create(MEDIA_TYPE_PNG, data); 
    Log.d(TAG, "requestBody: " + requestBody1.toString()); 
    RequestBody requestBody2 = new MultipartBuilder() 
      .type(MultipartBuilder.FORM) 
      .addFormDataPart("photo", "t.jpg", requestBody1) 
      .build(); 
    Log.d(TAG, "requestBody: " + requestBody2.toString()); 
// ProfileDetails profileDetails = new DBHelper(this).fetchProfileDetails(); 

    Call<Void> call = service.uploadUserProfilePhoto(5, requestBody2); 
    call.enqueue(new ProfilePhotoUploadCallback()); 
} 
+0

To działało jak czar dzięki. Uratowałeś mi dzień. –

+0

Tak, to działało również dla mnie. Wielkie dzięki! – Kaizie

+0

Dziękuję bardzo.! Uratowałeś mój dzień :) –

Powiązane problemy