2016-04-08 18 views
12

Sto provando a inviare file sul server utilizzando Retrofit2. Faccio tutto secondo la documentazione, ma ottengo sempre 400 errori del server.Retrofit - Richiesta multipart: Richiesto Il parametro "file" MultipartFile non è presente

che sto cercato di fare in questo modo:

RequestBody body = 
       RequestBody.create(MediaType.parse("image/png"), photo); 
    //.......... 

    @Multipart 
    @POST(ADD_PHOTO) 
    Observable<HPSPhotoResponse> 
    addPhoto(@Part("file") RequestBody file); 

... e in questo modo:

MultipartBody.Part part = MultipartBody.Part.createFormData("file", "file", body); 
    //........... 

    @Multipart 
    @POST(ADD_PHOTO) 
    Observable<HPSPhotoResponse> 
    addPhoto(@Part("file") MultipartBody.Part files); 

questione does't. Il risultato è sempre lo stesso "Richiesta multipart: Richiesto il parametro MultipartFile 'file' non è presente" - risposta del server.

Penso che Spring sul server non funzioni, ma faccio il codice equivalente su Swift (iOS) e funziona! Qui Server vede questa parte 'file'.

Alamofire.upload(method, endpoint, headers: headers, 
      multipartFormData: { multipartFormData in 
       multipartFormData.appendBodyPart(fileURL: self.filePath!, name: "file") 
      } 

Ora voglio che funzioni su Android con Retrofit. Ma guardo anche nei registri delle richieste di Retrofit e in effetti non vedo alcun testo "file" nei log.

Cosa c'è di sbagliato in questo?

risposta

23

È possibile provare il seguente codice di esempio. In questa app demo, caricaremo una foto dopo aver selezionato dalla Galleria. Spero che sia d'aiuto!

build.gradle di file:

dependencies { 
    ... 
    compile 'com.squareup.retrofit2:retrofit:2.0.1' 
    compile 'com.squareup.retrofit2:converter-gson:2.0.1' 
    ... 
} 

WebAPIService.java di file:

public interface WebAPIService { 

    @Multipart 
    @POST("/api/fileupload") 
    Call<ResponseBody> postFile(@Part MultipartBody.Part file, @Part("description") RequestBody description); 
} 

FileActivity.java di file:

... 
import okhttp3.MediaType; 
import okhttp3.MultipartBody; 
import okhttp3.RequestBody; 
import okhttp3.ResponseBody; 
import retrofit2.Call; 
import retrofit2.Callback; 
import retrofit2.Response; 
import retrofit2.Retrofit; 

public class FileActivity extends AppCompatActivity { 

    private final Context mContext = this; 
    private final String API_URL_BASE = "http://serverip:port"; 
    private final String LOG_TAG = "BNK"; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_file); 

     selectImage(); // selects a photo from Gallery 
    } 

    @Override 
    protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
     super.onActivityResult(requestCode, resultCode, data); 
     if (resultCode == Activity.RESULT_OK && requestCode == 100) { 
      Uri fileUri = data.getData(); 
      if (fileUri != null) { 
       uploadFile(fileUri); // uploads the file to the web service 
      } 
     } 
    } 

    private void uploadFile(Uri fileUri) { 

     String filePath = getRealPathFromUri(fileUri); 
     if (filePath != null && !filePath.isEmpty()) { 
      File file = new File(filePath); 
      if (file.exists()) { 
       Retrofit retrofit = new Retrofit.Builder() 
         .baseUrl(API_URL_BASE) 
         .build(); 

       WebAPIService service = retrofit.create(WebAPIService.class); 

       // creates RequestBody instance from file 
       RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); 
       // MultipartBody.Part is used to send also the actual filename 
       MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile); 
       // adds another part within the multipart request 
       String descriptionString = "Sample description"; 
       RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString); 
       // executes the request 
       Call<ResponseBody> call = service.postFile(body, description);     
       call.enqueue(new Callback<ResponseBody>() { 
        @Override 
        public void onResponse(Call<ResponseBody> call, 
              Response<ResponseBody> response) { 
         Log.i(LOG_TAG, "success"); 
        } 

        @Override 
        public void onFailure(Call<ResponseBody> call, Throwable t) { 
         Log.e(LOG_TAG, t.getMessage()); 
        } 
       }); 
      } 
     } 
    } 

    private void selectImage() { 
     Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 
     intent.setType("image/*"); 
     startActivityForResult(intent, 100); 
    } 

    public String getRealPathFromUri(final Uri uri) { 
     // DocumentProvider 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(mContext, uri)) { 
      // ExternalStorageProvider 
      if (isExternalStorageDocument(uri)) { 
       final String docId = DocumentsContract.getDocumentId(uri); 
       final String[] split = docId.split(":"); 
       final String type = split[0]; 

       if ("primary".equalsIgnoreCase(type)) { 
        return Environment.getExternalStorageDirectory() + "/" + split[1]; 
       } 
      } 
      // DownloadsProvider 
      else if (isDownloadsDocument(uri)) { 

       final String id = DocumentsContract.getDocumentId(uri); 
       final Uri contentUri = ContentUris.withAppendedId(
         Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); 

       return getDataColumn(mContext, contentUri, null, null); 
      } 
      // MediaProvider 
      else if (isMediaDocument(uri)) { 
       final String docId = DocumentsContract.getDocumentId(uri); 
       final String[] split = docId.split(":"); 
       final String type = split[0]; 

       Uri contentUri = null; 
       if ("image".equals(type)) { 
        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 
       } else if ("video".equals(type)) { 
        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; 
       } else if ("audio".equals(type)) { 
        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 
       } 

       final String selection = "_id=?"; 
       final String[] selectionArgs = new String[]{ 
         split[1] 
       }; 

       return getDataColumn(mContext, contentUri, selection, selectionArgs); 
      } 
     } 
     // MediaStore (and general) 
     else if ("content".equalsIgnoreCase(uri.getScheme())) { 

      // Return the remote address 
      if (isGooglePhotosUri(uri)) 
       return uri.getLastPathSegment(); 

      return getDataColumn(mContext, uri, null, null); 
     } 
     // File 
     else if ("file".equalsIgnoreCase(uri.getScheme())) { 
      return uri.getPath(); 
     } 

     return null; 
    } 

    private String getDataColumn(Context context, Uri uri, String selection, 
             String[] selectionArgs) { 

     Cursor cursor = null; 
     final String column = "_data"; 
     final String[] projection = { 
       column 
     }; 

     try { 
      cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, 
        null); 
      if (cursor != null && cursor.moveToFirst()) { 
       final int index = cursor.getColumnIndexOrThrow(column); 
       return cursor.getString(index); 
      } 
     } finally { 
      if (cursor != null) 
       cursor.close(); 
     } 
     return null; 
    } 

    private boolean isExternalStorageDocument(Uri uri) { 
     return "com.android.externalstorage.documents".equals(uri.getAuthority()); 
    } 

    private boolean isDownloadsDocument(Uri uri) { 
     return "com.android.providers.downloads.documents".equals(uri.getAuthority()); 
    } 

    private boolean isMediaDocument(Uri uri) { 
     return "com.android.providers.media.documents".equals(uri.getAuthority()); 
    } 

    private boolean isGooglePhotosUri(Uri uri) { 
     return "com.google.android.apps.photos.content".equals(uri.getAuthority()); 
    } 
} 
+2

Yeah !!! Grazie mille che posso :) !!! Ha aiutato. ... Il problema principale era esattamente nel retrofit "... retrofit: 2.0.0" invece "..retrofit: 2.0.1". In questa versione qualcosa non va con l'annotazione "MultipartBody.Part" L'ho cambiato e ha funzionato esattamente come iOS. Grazie ancora. –

+0

Come inviare un'immagine con parametro se aggiungo immagine con il parametro poi java.lang.IllegalArgumentException:? Parametri @Part utilizzando l'MultipartBody.Part non devono includere un nome parte l'annotazione – Suman

+0

@Suman non ho testato con retrofit per mesi , tuttavia, puoi provare ad usare '@Part (" description ") RequestBody description' come il mio codice sopra o menzionato su http://square.github.io/retrofit/ – BNK

0

Nel mio caso il server non stava gestendo alcune intestazioni che il retrofit sta inviando. Ecco perché ho dovuto rimuovere l'intestazione inutile dalle richieste di retrofit. Ho creato funzione di interfaccia come questa:

@POST("my/files/photo/") 
Call<FileUploadResponse> uploadPhoto(@Header("Content-Type") String contentType, 
              @Header("Authorization") String auth, 
              @Body MultipartBody body); 

e chiamare le cose come:

ApiClient.ApiInterface client = ApiClient.getClient(); 
File file = new File(getPathFromUri(fileUri)); 
RequestBody fileBody = RequestBody.create(MediaType.parse(getContentResolver().getType(fileUri)), file); 
MultipartBody body = new MultipartBody.Builder().addFormDataPart("file-type", "profile") 
       .addFormDataPart("photo", "image.png", fileBody) 
       .build(); 
client.uploadPhoto("multipart/form-data; boundary=" + body.boundary(), 
        PrefManager.getInstance().getToken(), body); 

vedi dettagli qui: Upload picture to server using retrofit 2

Problemi correlati