使用@PartMap 或任何等效于@FieldMap 的多部分发出多部分HTTP POST 请求

Making a Multipart HTTP POST request with @PartMap or any multipart equivalent to @FieldMap

我需要使用 form-data POST 上传文件和 JSON Object 个字符串,我的界面如下所示:

public interface uploadService {
     @Multipart
     @POST
     Call<Void> uploadPhoto(@Part("photo") File file,
            @PartMap Map<String, Object> params);
}

我遇到错误 End of Line 1 at Column 1,我的 Callback 继续使用 OnError(...) 方法。简而言之,我的 HTTP 请求没有成功。我在想我哪里错了。

非常感谢您的回答。

PS: 请不要建议我使用 MultipartEntity extends HttpEntity 我已经读到它现在已被弃用。谢谢!

单独使用 PartMap 就足以处理多部分。 使用

 @Multipart
    @POST("api/registration")
    Call<UserDetails> registerUser (@Header("Content-Length") long contentLength, @PartMap Map<String, RequestBody> params);

你可以创建一个 Requestody 来保存像

这样的文件
RequestBody.create(MediaType.parse("image/*"), file);

并将其添加到零件图中。

Map<String, RequestBody> params; // 创建所有类型的 requestbody 并将其添加到此映射。 您可以通过

计算内容长度
 long contentLength = 0;
        Iterator iterator = params.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry pair = (Map.Entry)iterator.next();
            try {
                contentLength = contentLength + ((RequestBody)pair.getValue()).contentLength();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

。如果你想听文件上传的进度,那么你可以扩展 RequestBody 来提供有关进度的信息。

public class ProgressRequestBody extends RequestBody {

private File file;
private ProgressListener listener;
private int DEFAULT_BUFFER_SIZE = 4084;

@Override
public MediaType contentType() {
    return MediaType.parse("image/*");
}

//The constructor
public ProgressRequestBody(final File file, final ProgressListener listener) {
    this.file = file;
    this.listener = listener;
}

//The method to overide
@Override
public void writeTo(BufferedSink sink) throws IOException {
    long fileLength = file.length();
    byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
    FileInputStream in = new FileInputStream(file);
    long total = 0;
    try {
        int read;
        while ((read = in.read(buffer)) != -1) {
            this.listener.onProgress(total, fileLength);
            total += read;
            sink.write(buffer, 0, read);
        }
    } finally {
        in.close();
    }
}

//A simple callback
public interface ProgressListener {
    void onProgress(final long current, final long max);
}

}

并用它来像

一样包装文件
 public static RequestBody toImageRequestBody(File file, ProgressListener progressListener) {
        ProgressRequestBody progressRequestBody = new ProgressRequestBody(file, progressListener);
        return progressRequestBody;
    }

保留它作为奖励 ;)

以下对我有用

界面

@Multipart
@POST("user/upload")
Call<JsonElement> upload(@PartMap Map<String, RequestBody> params);, user.getToken());

发送数据和图片如下

LinkedHashMap<String, RequestBody> mp= new LinkedHashMap<>();
RequestBody userId = RequestBody.create(
                        okhttp3.MediaType.parse("text/plain"), user.getUserId());
RequestBody userToken = RequestBody.create(
                        okhttp3.MediaType.parse("text/plain"), user.getToken());

//Instead of "text/plain" you can also send Json
mp.put("user_id", userId);
mp.put("token", userToken);


avatarFile = new File(uri.getPath());

RequestBody fileBody = RequestBody.create(MediaType.parse("image/gif"), avatarFile);

mp.put("files\"; filename=\"image.gif\"", fileBody);