Android在单个请求中上传多个文件 [英] Android Upload Multiple Files In A Single Request

查看:75
本文介绍了Android在单个请求中上传多个文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过 multipart/form-data 请求将内容发布到服务器. 并且我发布的数据包含多个参数,包括文件数组参数(files []).

I'm posting content to the server in a multipart/form-data request. and the data I'm posting contains multiple parameters including a file array parameter (files[]).

使用邮递员我正在设置参数,然后文件为:

Using postman I'm setting the parameters and the files as:

first-parameter=text content
second-parameter=text content
files[0]={first selected file}
files[1]={second selected file}

向邮递员提交此请求总是成功的,并且文件已成功上传.

Submitting this request on postman is always successful, and the files are uploaded successfully.

当我在邮递员上生成代码片段时,结果如下:

When I generate code snippets on postman, this is the result:

POST /api/*******/new HTTP/1.1
Host: ***.***.***.*** ip-address
Authorization: {authorization header}
Cache-Control: no-cache
Postman-Token: d15f13f1-4a65-81d1-bf91-f5accd1b1dd0
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="first-parameter"

first-parameter-value
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="second-parameter"

second-parameter-value
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="files[0]"; filename=""
Content-Type: 

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="files[1]"; filename=""
Content-Type: 

------WebKitFormBoundary7MA4YWxkTrZu0gW--

在Android上,我正在将Retrofit与HttpLoggingInterceptor库一起使用,并在发布请求时使用@PartMap批注:

On Android, I'm using Retrofit with the HttpLoggingInterceptor libraries, and using the @PartMap annotation when posting the request:

//API定义:

interface ApiDefinitions {

@Multipart
@POST("*******/new")
Call<ApiResponse> submitNew(@Header("Authorization") String authHeader,
                                      @PartMap Map<String, RequestBody> params);

}

//准备并发送请求代码:

//Preparing and sending the request code:

public void postContent() {
    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

    OkHttpClient client = new OkHttpClient
            .Builder()
            .addInterceptor(interceptor)
            .build();

    Retrofit retrofit = new Retrofit
            .Builder()
            .baseUrl(API_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create(new Gson()))
            .build();

    ApiDefinitions api = retrofit.create(ApiDefinitions.class);

    MediaType mediaType = MediaType.parse("multipart/form-data");

    Map<String, RequestBody> params = new HashMap<>();
    params.put("first-parameter", MultipartBody.create(mediaType, "first-parameter-value"));
    params.put("second-parameter", MultipartBody.create(mediaType, "second-parameter-value"));
    params.put("files[0]", MultipartBody.create(mediaType, new File("First file path")));
    params.put("files[1]", MultipartBody.create(mediaType, new File("Second file path")));

    Call<ApiResponse> call = api.submitNew("Auth Token", params);
    enqueue.enqueue(new Callback<ApiResponse>() {

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

        @Override
        public void onFailure(Call<ApiResponse> call, Throwable t) {
        }
    });
}

提交此请求没有任何错误,http响应为200,但是文件未上传!

Submitting this request works with no errors, http response is 200, But the files are not uploaded !!!

由于我使用的是HttpLoggingInterceptor,因此我尝试将改造日志与邮编代码段进行比较,这就是改造日志:

Since I'm using the HttpLoggingInterceptor, I've tried comparing the retrofit logs with post man code snippets, this is the retrofit log:

D/OkHttp: --> POST http://{api_address}/api/*****/new http/1.1
D/OkHttp: Content-Type: multipart/form-data; boundary=64360751-a7f4-44c4-a008-f5de764c7298
D/OkHttp: Content-Length: 119325
D/OkHttp: Authorization: {Authorization-Token}
D/OkHttp: --64360751-a7f4-44c4-a008-f5de764c7298
D/OkHttp: Content-Disposition: form-data; name="first-parameter"
D/OkHttp: Content-Transfer-Encoding: binary
D/OkHttp: Content-Type: multipart/form-data; charset=utf-8
D/OkHttp: Content-Length: 10
D/OkHttp: first-parameter-value
D/OkHttp: --64360751-a7f4-44c4-a008-f5de764c7298
D/OkHttp: Content-Disposition: form-data; name="second-parameter"
D/OkHttp: Content-Transfer-Encoding: binary
D/OkHttp: Content-Type: multipart/form-data; charset=utf-8
D/OkHttp: Content-Length: 10
D/OkHttp: second-parameter-value
D/OkHttp: --64360751-a7f4-44c4-a008-f5de764c7298
D/OkHttp: Content-Disposition: form-data; name="files[0]"
D/OkHttp: Content-Transfer-Encoding: binary
D/OkHttp: Content-Type: multipart/form-data;
D/OkHttp: Content-Length: 44205
D/OkHttp: �PNG
D/OkHttp: 
D/OkHttp: ������IHDR��������������������r�B�������sBIT��O����� ��IDATx�4�˳mYv��}c�9���so�|W���R��2z�T%�8B�X� 
D/OkHttp: &�D$��B��r�D��w�!@��������{��H���[�!,�@ �4h�P����>�A��&� ����B�[�,�fD�Mi�d�5)���5�{��-�MQt��ٗ&
D/OkHttp: --64360751-a7f4-44c4-a008-f5de764c7298
D/OkHttp: Content-Disposition: form-data; name="files[1]"
D/OkHttp: Content-Transfer-Encoding: binary
D/OkHttp: Content-Type: multipart/form-data;
D/OkHttp: Content-Length: 44205
D/OkHttp: �PNG
D/OkHttp: 
D/OkHttp: ������IHDR��������������������r�B�������sBIT��O����� ��IDATx�4�˳mYv��}c�9���so�|W���R��2z�T%�8B�X� 
D/OkHttp: &�D$��B��r�D��w�!@��������{��H���[�!,�@ �4h�P����>�A��&� ����B�[�,�fD�Mi�d�5)���5�{��-�MQt��ٗ&
D/OkHttp: --64360751-a7f4-44c4-a008-f5de764c7298--
D/OkHttp: --> END POST (119325-byte body)
D/OkHttp: <-- 200 OK http://{api_address}/api/*****/new (3409ms)

我试图通过比较邮递员和改版的两个日志来查找请求中的问题,但是我找不到它! 随机的边界字符串是不同的,这很正常,邮递员使用webkit,而改造则没有!我根本不认为这是个问题.

I've tried to find what's wrong in my request by comparing both logs from postman vs retrofit, but I can't find it ! The random boundary strings are different which is normal, postman uses webkit, while retrofit does not ! I don't think this is an issue at all.

我已尝试按照建议在这里,但它也无法正常工作.

I've tried to use @Part List<MultipartBody.Part instead of @PartMap Map<String, RequestBody> for the files as suggested here, but it didn't work also.

要上传的文件我应该怎么做?

What should I do for the files to be uploaded ?

推荐答案

首先,我做错了一件事情,那就是在ApiDefinitions界面中使用@PartMap Map<String, RequestBody>.

First of all, I've been doing one thing wrong which is using a @PartMap Map<String, RequestBody> in the ApiDefinitions interface.

如果您要执行具有多个参数和多个文件的发布请求,请始终确保在定义api方法时将RequestBody用于非文件参数,并将MultipartBody.Part用于文件参数.

In case you're doing a post request with multiple parameters and multiple files, always make sure when defining the api method to use RequestBody for non-file parameters, and use MultipartBody.Part for file parameters.

就我而言,我需要发送文件数组,因此对我有用的参数是MultipartBody.Part[].

In my case I needed to send an array of files, so the parameter that has worked for me is MultipartBody.Part[].

这是新的api定义:

@Multipart
@POST("*******/new")
Call<ApiResponse> submitNew(@Header("Authorization") String authHeader,
                                          @Part("first-parameter") RequestBody firstParameter,
                                          @Part("first-parameter") RequestBody secondParameter,
                                          @Part MultipartBody.Part[] files);

我犯的第二个错误是没有注意到这一点:

The second mistake I made was not noticing this:

PostMan日志:Content-Disposition:表单数据; name ="files [0]"; filename ="

PostMan Log: Content-Disposition: form-data; name="files[0]"; filename=""

改造日志:内容处置:表单数据; name ="files [0]"

Retrofit Log: Content-Disposition: form-data; name="files[0]"

文件名未包含在多部分请求中,这显然是将文件上传到文件时的已知问题php服务

The filename was not included in the multipart request, which apparently is a known issue when uploading files to a php service !

我没有制作api,并且我没有任何php背景,所以请不要判断我. 据我所知,我已经成功地将文件发送到服务api,但是api不知道如何保存这些文件!

I didn't make the api, and I don't have any php background so please don't judge me. As far as I know, I was successfully sending files to the service api, but the api didn't know how to save these files !

因此,在发送请求时:

List<Uri> files; //These are the uris for the files to be uploaded
MediaType mediaType = MediaType.parse("");//Based on the Postman logs,it's not specifying Content-Type, this is why I've made this empty content/mediaType
MultipartBody.Part[] fileParts = new MultipartBody.Part[files.size()];
for (int i = 0; i < files.size(); i++) {
    File file = new File(files.get(i).getPath());
    RequestBody fileBody = RequestBody.create(mediaType, file);
    //Setting the file name as an empty string here causes the same issue, which is sending the request successfully without saving the files in the backend, so don't neglect the file name parameter.
    fileParts[i] = MultipartBody.Part.createFormData(String.format(Locale.ENGLISH, "files[%d]", i), file.getName(), fileBody);
}

Call<ApiResponse> call = api.submitNew("Auth Token", MultipartBody.create(mediaType, "first_parameter_values"), MultipartBody.create(mediaType, "second_parameter_values"), fileParts);

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

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

    @Override
    public void onFailure(Call<ApiResponse> call, Throwable t) {
    }
});

这篇关于Android在单个请求中上传多个文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆