6

AndroidでRetrofit 1.8.0を使用してマルチパートリクエストを作成しようとして、4日ほどかかりました。私のインターフェースは次のようになります

@Multipart
@POST("/posts/add.json") 
void addComment(
  @Part("id") String id,
  @Part("post[body]") String body,
  @Part("post[attachment]") TypedFile attachment,
  Callback<Map<String, String>> callback );

しかし、サーバー側では、次のメッセージを受け取ります

Parameters: {"id"=># <File:/var/folders/z0/0ggjvvfj4t1fdsvbxf3lc9pw0000gn/T/RackMultipart9853-0>, "post"=>{"body"=>#<File:/var/folders/z0/0ggjvvfj4t1fdsvbxf3lc9pw0000gn/T/RackMultipart9853-1>, "attachment"=>#<File:/var/folders/z0/0ggjvvfj4t1fdsvbxf3lc9pw0000gn/T/RackMultipart9853-2>}, "controller"=>"posts", "action"=>"add", "format"=>"json"}

ご覧のとおり、ファイル部分はすべての部分でそれを送信していますが、id と post[body] のパラメーターの値がありません

Retrofit が送信しようとしているのは次のとおりです。

 02-06 15:01:16.213    32545-822/com.myapp D/Retrofit﹕ --fe41634b-6826-4ee4-95cb-65efb0ca66c2
Content-Disposition: form-data; name="id"
Content-Type: text/plain; charset=UTF-8
Content-Length: 3
Content-Transfer-Encoding: binary
189
--fe41634b-6826-4ee4-95cb-65efb0ca66c2
Content-Disposition: form-data; name="post[body]"
Content-Type: text/plain; charset=UTF-8
Content-Length: 4
Content-Transfer-Encoding: binary
test
--fe41634b-6826-4ee4-95cb-65efb0ca66c2
Content-Disposition: form-data; name="post[attachment]"; filename="IMG_20140203_144358.jpg"
Content-Type: image/jpg
Content-Length: 1615460
Content-Transfer-Encoding: binary
����/�Exif����MM��*���������

これは、HttpMime ライブラリがマルチパートで送信しているものです。違いは、Retrofit に対する「Content-Transfer-Encoding」ヘッダーです。

Content-Disposition: form-data; name="id"
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 8bit

Content-Disposition: form-data; name=“post[body]"
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 8bit

Content-Disposition: form-data; name=“post[attachment]"; filename="images.jpg"
Content-Type: image/jpg
Content-Transfer-Encoding: binary

どんな手掛かり?前もって感謝します

- - - - - - - - - - - - - - - -解決 - - - - - - - - - ----------------

最後に、私はこのように解決しました。実際、私の答えは@lazypigにかなり近いです。これは良いガイドラインでした

私が変更した唯一のものは、彼のクラス「ByteArrayTypedOutput」でした

「MultipartTypedOutputCustom」というクラスを作成しましたhttp://pastie.org/10549360

そして、これが私のインターフェースの外観です

「PostsRetrofitAPI.java」クラス

@POST("/posts/add.json")
    void addComment(@Body MultipartTypedOutputCustom parts,
                    Callback<Map<String, String>> callback);

「PostsService.java」クラス

//Properties
private PostsRetrofitAPI mApi;
...

    @Override
        public void addComment(ServiceResponseHandler<Map<String, String>> handler, String id, String body, TypedFile attachment) {
           MultipartTypedOutputCustom parts = new MultipartTypedOutputCustom();
           parts.addPart("id", new TypedString(id));
           parts.addPart("post[body]", new TypedString(body));
           parts.addPart("post[attachment]", attachment);
    objectRetrofitCallback= new ObjectRetrofitCallback(handler, ServerError.class, ClientError.class);
            mApi.addComment(parts, objectRetrofitCallback);
        }
4

3 に答える 3

3

http://square.github.io/retrofit/の例を見ると、「id」および「part[body]」パラメータのオブジェクト タイプは、String ではなく TypedString である必要があります。TypedString は適切な MIME タイプを設定し、バイトに変換します。

https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit/mime/TypedString.java

于 2014-02-06T20:31:28.960 に答える
0

今日、ファイルといくつかのフィールドを送信するために同様の問題がありました。これが私の解決策です

私のインターフェース TypedFile は Retrofit クラスです

    @Multipart
    @POST("/api/Media/add")
    void addMedia(@Part("file") TypedFile photo,
                  @Part("type") String type,
                  @Part("name") String name,
                  @Part("description") String description,
                  Callback<com.yourcompany.pojo.Media> callback);

活動中

profileImage.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent galleryIntent = new Intent(
                    Intent.ACTION_PICK,
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            startActivityForResult(galleryIntent , RESULT_GALLERY );
        }
    });

その後

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    switch (requestCode) {
        case RESULT_GALLERY :
            if (null != data) {
                imageUri = data.getData();
                String selectedImagePath = null;
                Uri selectedImageUri = data.getData();
                Cursor cursor = activity.getContentResolver().query(selectedImageUri, null, null,
                null, null);
                if (cursor == null) {
                    selectedImagePath = imageUri.getPath();
                } else {
                    cursor.moveToFirst();
                    int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
                    selectedImagePath = cursor.getString(idx);
                }
                File file = new File(selectedImagePath);
                waiter.setVisibility(View.VISIBLE);
                _YOUR_APP_._YOUR_INTERFACE_.addMedia(new TypedFile("image/*", file), "avatar", "avatar", "avatar", new Callback<Media>() {

                    @Override
                    public void success(Media media, Response response) {

                    }

                    @Override
                    public void failure(RetrofitError error) {

                    }
                });
            }
            break;
        default:
            break;
    }
}

メディアクラスは、答えを維持するための単純なポジョです

public class Media {

@Expose
private int[] data;

/**
 *
 * @return
 * The data
 */
public int getData() {
    return data[0];
}

/**
 *
 * @param data
 * The data
 */
public void setData(int[] data) {
    this.data = data;
}

}
于 2015-05-05T10:22:43.030 に答える