2016-04-08 21 views
12

Retrofit2を使用してサーバー上のファイルを送信しようとしています。 私はドキュメントに従ってすべてを行いますが、常に400のサーバーエラーが発生します。Retrofit - Multipart request:必須MultipartFileパラメーター 'file'がありません。

私はこのように実行しようとしましたよ:

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

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

...と、このような:

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

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

does't問題。結果は常に同じです "Multipart request:必須MultipartFileパラメータ 'file'は存在しません" - サーバレスポンス。

私は、サーバー上のSpringはうまくいかないと思っていますが、私はSwift(iOS)で同等のコードを実行しています。ここでサーバーはこの 'ファイル'部分を見ます。

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

今、私はそれがAndroidでRetrofitで動作します。 しかし、Retrofitリクエストのログを調べても、実際にはログに「ファイル」テキストが表示されません。

どうしたのですか?

答えて

23

次のサンプルコードを試すことができます。このデモアプリケーションでは、ギャラリーから選択して写真をアップロードします。それが役に立てば幸い!

build.gradleファイル:

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

WebAPIService.javaファイル:

public interface WebAPIService { 

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

FileActivity.javaファイル:

... 
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

うん!私がすることができる最大の感謝:)!それは助けになった。 ...主な問題は正確に "retrofit:2.0.0"の代わりに "retrofit:2.0.1"に改造されたものです。このバージョンでは、注釈「MultipartBody.Part」の何かが間違っています 私はそれを変更して、iOSとまったく同じ働きをしています。再度、感謝します。 –

+0

パラメータを使用してイメージを送信する方法?パラメータを指定してイメージを追加すると、java.lang.IllegalArgumentException:MultipartBody.Partを使用する@Partパラメータに注釈に部品名を含めないでください – Suman

+0

@Suman月間Retrofitでテストしていませんしかし、あなたは@Part( "description")RequestBody description'を上記の私のコードとして試してみるか、http://square.github.io/retrofit/ – BNK

0

私の場合、サーバは、改造した送信ヘッダを処理していませんでした。だからこそ、改造要求から無駄なヘッダを取り除かなければならなかったのです。

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

など、それを呼び出す:私はこのようなインタフェース機能を作成しました

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); 

はここに詳細を参照してください。Upload picture to server using retrofit 2

関連する問題