182

Retrofit 2.0を使用してサーバーに HTTP POST を実行しようとしています。

MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
MediaType MEDIA_TYPE_IMAGE = MediaType.parse("image/*");

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    imageBitmap.compress(Bitmap.CompressFormat.JPEG,90,byteArrayOutputStream);
profilePictureByte = byteArrayOutputStream.toByteArray();

Call<APIResults> call = ServiceAPI.updateProfile(
        RequestBody.create(MEDIA_TYPE_TEXT, emailString),
        RequestBody.create(MEDIA_TYPE_IMAGE, profilePictureByte));

call.enqueue();

サーバーは、ファイルが無効であることを示すエラーを返します。

これは、iOS で同じ形式の同じファイルを (他のライブラリを使用して) アップロードしようとしたため、奇妙です。ただし、正常にアップロードされます。

Retrofit 2.0を使用して画像をアップロードする適切な方法は何ですか?

アップロードする前にディスクに保存する必要がありますか?

PS: 画像を含まない他のマルチパート リクエストにレトロフィットを使用しましたが、正常に完了しました。問題は、ボディにバイトを含めようとしているときです。

4

13 に答える 13

207

ハックせずに、Retrofit 2でその名前のファイルをアップロードする正しい方法があります。

API インターフェイスを定義します。

@Multipart
@POST("uploadAttachment")
Call<MyResponse> uploadAttachment(@Part MultipartBody.Part filePart); 
                                   // You can add other parameters too

次のようにファイルをアップロードします。

File file = // initialize file here

MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), RequestBody.create(MediaType.parse("image/*"), file));

Call<MyResponse> call = api.uploadAttachment(filePart);

これはファイルのアップロードのみを示しています@Part。注釈を使用して同じメソッドに他のパラメーターを追加することもできます。

于 2016-08-11T08:23:53.780 に答える
201

一部の場合に役立つため、1.9 と 2.0 の両方でソリューションを強調しています。

では1.9、より良い解決策は、ファイルをディスクに保存し、次のように型付きファイルとして使用することだと思います。

レトロフィット 1.9

(サーバー側の実装については知りません)これに似たAPIインターフェースメソッドがあります

@POST("/en/Api/Results/UploadFile")
void UploadFile(@Part("file") TypedFile file,
                @Part("folder") String folder,
                Callback<Response> callback);

そして、それを次のように使用します

TypedFile file = new TypedFile("multipart/form-data",
                                       new File(path));

RetroFit 2 の場合、次の方法を使用します

RetroFit 2.0 (これは現在修正されている RetroFit 2の問題の回避策でした。正しい方法については、 jimmy0251 の回答を参照してください)

API インターフェイス:

public interface ApiInterface {

    @Multipart
    @POST("/api/Accounts/editaccount")
    Call<User> editUser(@Header("Authorization") String authorization,
                        @Part("file\"; filename=\"pp.png\" ") RequestBody file,
                        @Part("FirstName") RequestBody fname,
                        @Part("Id") RequestBody id);
}

次のように使用します。

File file = new File(imageUri.getPath());

RequestBody fbody = RequestBody.create(MediaType.parse("image/*"),
                                       file);

RequestBody name = RequestBody.create(MediaType.parse("text/plain"),
                                      firstNameField.getText()
                                                    .toString());

RequestBody id = RequestBody.create(MediaType.parse("text/plain"),
                                    AZUtils.getUserId(this));

Call<User> call = client.editUser(AZUtils.getToken(this),
                                  fbody,
                                  name,
                                  id);

call.enqueue(new Callback<User>() {

    @Override
    public void onResponse(retrofit.Response<User> response,
                           Retrofit retrofit) {

        AZUtils.printObject(response.body());
    }

    @Override
    public void onFailure(Throwable t) {

        t.printStackTrace();
    }
});
于 2016-01-02T05:37:04.463 に答える
20

Retrofit2.0で画像ファイルをアップロードするための更新コード

public interface ApiInterface {

    @Multipart
    @POST("user/signup")
    Call<UserModelResponse> updateProfilePhotoProcess(@Part("email") RequestBody email,
                                                      @Part("password") RequestBody password,
                                                      @Part("profile_pic\"; filename=\"pp.png")
                                                              RequestBody file);
}

MediaType.parse("image/*")に変更MediaType.parse("image/jpeg")

RequestBody reqFile = RequestBody.create(MediaType.parse("image/jpeg"),
                                         file);
RequestBody email = RequestBody.create(MediaType.parse("text/plain"),
                                       "upload_test4@gmail.com");
RequestBody password = RequestBody.create(MediaType.parse("text/plain"),
                                          "123456789");

Call<UserModelResponse> call = apiService.updateProfilePhotoProcess(email,
                                                                    password,
                                                                    reqFile);
call.enqueue(new Callback<UserModelResponse>() {

    @Override
    public void onResponse(Call<UserModelResponse> call,
                           Response<UserModelResponse> response) {

        String
                TAG =
                response.body()
                        .toString();

        UserModelResponse userModelResponse = response.body();
        UserModel userModel = userModelResponse.getUserModel();

        Log.d("MainActivity",
              "user image = " + userModel.getProfilePic());

    }

    @Override
    public void onFailure(Call<UserModelResponse> call,
                          Throwable t) {

        Toast.makeText(MainActivity.this,
                       "" + TAG,
                       Toast.LENGTH_LONG)
             .show();

    }
});
于 2016-08-06T05:44:14.827 に答える
5

kotlin では、 toMediaTypeasRequestBody、およびtoRequestBodyの拡張メソッドを使用すると、非常に簡単です。例を次に示します。

ここでは、マルチパートを使用して、pdf ファイルと画像ファイルとともに、いくつかの通常のフィールドを投稿しています。

これはレトロフィットを使用した API 宣言です。

    @Multipart
    @POST("api/Lesson/AddNewLesson")
    fun createLesson(
        @Part("userId") userId: RequestBody,
        @Part("LessonTitle") lessonTitle: RequestBody,
        @Part pdf: MultipartBody.Part,
        @Part imageFile: MultipartBody.Part
    ): Maybe<BaseResponse<String>>

実際に呼び出す方法は次のとおりです。

api.createLesson(
            userId.toRequestBody("text/plain".toMediaType()),
            lessonTitle.toRequestBody("text/plain".toMediaType()),
            startFromRegister.toString().toRequestBody("text/plain".toMediaType()),
            MultipartBody.Part.createFormData(
                "jpeg",
                imageFile.name,
                imageFile.asRequestBody("image/*".toMediaType())
            ),
            MultipartBody.Part.createFormData(
                "pdf",
                pdfFile.name,
                pdfFile.asRequestBody("application/pdf".toMediaType())
            )
于 2020-05-10T11:59:00.480 に答える
1

廃止のための更新を含む Kotlin バージョンRequestBody.create:

後付けインターフェース

@Multipart
@POST("uploadPhoto")
fun uploadFile(@Part file: MultipartBody.Part): Call<FileResponse>

そしてアップロードへ

fun uploadFile(fileUrl: String){
    val file = File(fileUrl)
    val fileUploadService = RetrofitClientInstance.retrofitInstance.create(FileUploadService::class.java)
    val requestBody = file.asRequestBody(file.extension.toMediaTypeOrNull())
    val filePart = MultipartBody.Part.createFormData(
        "blob",file.name,requestBody
    )
    val call = fileUploadService.uploadFile(filePart)

    call.enqueue(object: Callback<FileResponse>{
        override fun onFailure(call: Call<FileResponse>, t: Throwable) {
            Log.d(TAG,"Fckd")
        }

        override fun onResponse(call: Call<FileResponse>, response: Response<FileResponse>) {
            Log.d(TAG,"success"+response.toString()+" "+response.body().toString()+"  "+response.body()?.status)
        }

    })
}

@ jimmy0251に感謝

于 2019-10-23T07:11:41.937 に答える
0

関数名に複数のパラメーターを 使用しないでください。コードの読みやすさを向上させる単純ないくつかの引数の規則に従ってください。これは、次のように行うことができます-

// MultipartBody.Part.createFormData("partName", data)
Call<SomReponse> methodName(@Part MultiPartBody.Part part);
// RequestBody.create(MediaType.get("text/plain"), data)
Call<SomReponse> methodName(@Part(value = "partName") RequestBody part); 
/* for single use or you can use by Part name with Request body */

// add multiple list of part as abstraction |ease of readability|
Call<SomReponse> methodName(@Part List<MultiPartBody.Part> parts); 
Call<SomReponse> methodName(@PartMap Map<String, RequestBody> parts);
// this way you will save the abstraction of multiple parts.

Retrofit の使用中に複数の例外が発生する可能性があります。コードとして文書化されているすべての例外には、 へのウォークスルーがありretrofit2/RequestFactory.javaます。2 つの関数parseParameterAnnotationparseMethodAnnotation使用でき、例外をスローできる場合は、これを実行してください。グーグル/スタックオーバーフローよりも多くの時間を節約できます

于 2020-03-15T18:36:43.877 に答える