Aye*_*ieh 3 android multipartform-data retrofit2
我在多部分/表单数据请求中将内容发布到服务器。并且我发布的数据包含多个参数,包括文件数组参数 (files[])。
使用邮递员,我将参数和文件设置为:
first-parameter=text content
second-parameter=text content
files[0]={first selected file}
files[1]={second selected file}
Run Code Online (Sandbox Code Playgroud)
在邮递员上提交这个请求总是成功的,文件上传成功。
当我在邮递员上生成代码片段时,结果如下:
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--
Run Code Online (Sandbox Code Playgroud)
在 Android 上,我将 Retrofit 与 HttpLoggingInterceptor 库一起使用,并在发布请求时使用 @PartMap 注释:
//API定义:
interface ApiDefinitions {
@Multipart
@POST("*******/new")
Call<ApiResponse> submitNew(@Header("Authorization") String authHeader,
@PartMap Map<String, RequestBody> params);
}
Run Code Online (Sandbox Code Playgroud)
//准备和发送请求代码:
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) {
}
});
}
Run Code Online (Sandbox Code Playgroud)
提交这个请求没有错误,http响应是200,但是文件没有上传!!!
由于我使用的是 HttpLoggingInterceptor,因此我尝试将改造日志与 post man 代码片段进行比较,这是改造日志:
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)
Run Code Online (Sandbox Code Playgroud)
我试图通过比较邮递员与改造的两个日志来找出我的请求中的问题,但我找不到!随机边界字符串不同这是正常的,postman 使用 webkit,而retrofit 没有!我认为这根本不是问题。
我尝试按照此处的建议使用@Part List<MultipartBody.Part而不是@PartMap Map<String, RequestBody>用于文件,但它也不起作用。
我应该如何处理要上传的文件?
首先,我一直在做错一件事,那就是@PartMap Map<String, RequestBody>在ApiDefinitions界面中使用了 a 。
如果您正在执行具有多个参数和多个文件的 post 请求,请始终确保在定义RequestBody用于非文件参数的 api 方法和MultipartBody.Part用于文件参数时。
就我而言,我需要发送一组文件,因此对我有用的参数是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);
Run Code Online (Sandbox Code Playgroud)
我犯的第二个错误是没有注意到这一点:
邮递员日志:内容配置:表单数据;名称=“文件[0]”;文件名=""
改造日志:Content-Disposition:form-data;名称=“文件[0]”
文件名未包含在多部分请求中,这显然是将文件上传到 php 服务时的一个已知问题!
我没有制作api,我没有任何php背景所以请不要评判我。据我所知,我已经成功地将文件发送到服务 api,但 api 不知道如何保存这些文件!
所以在发送请求时:
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) {
}
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11214 次 |
| 最近记录: |