2016-12-17 77 views
1

我向multipart/form-data請求發佈內容到服務器。 我發佈的數據包含多個參數,包括文件數組參數(files [])。Android在單個請求中上傳多個文件

使用postman我設置參數和文件,如:

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

提交的郵遞員這個要求總是成功的,並且這些文件上傳成功。

當我產生對郵遞員的代碼段,這是結果:

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上,我使用的是改造與HttpLoggingInterceptor庫,並張貼請求時使用@PartMap註釋:

// API定義:

interface ApiDefinitions { 

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

} 

//準備和發送請求的代碼:

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,但是文件沒有上傳!

由於我使用的是HttpLoggingInterceptor,我試過比較郵遞員代碼段改造日誌,這是改造日誌:

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�[email protected]��������{��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�[email protected]��������{��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,而改造不!我不認爲這是一個問題。

我試過使用@Part List<MultipartBody.Part而不是@PartMap Map<String, RequestBody>作爲建議here的文件,但它也沒有工作。

我應該如何處理要上傳的文件?

回答

2

首先,我一直在做一件錯誤的事情,它在ApiDefinitions接口中使用@PartMap Map<String, RequestBody>

如果您正在使用多個參數和多個文件進行發佈請求,請務必確保在定義api方法時使用RequestBody作爲非文件參數,並使用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); 

我犯了第二個錯誤是沒有注意到這一點:

郵遞員日誌:內容處置:表格數據;名稱= 「文件[0]」; filename =「」

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

文件名不包含在multipart請求中,顯然是known issue when uploading files to a php service

我沒有製作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) { 
    } 
}); 
+1

謝謝@Ayesh,你的回答很有魅力 –

0

我認爲你應該改變文件的MediaType。並且您還檢查https://futurestud.io/tutorials/retrofit-2-how-to-upload-files-to-server的鏈接並使用@Part MultipartBody發送文件。部分

MediaType mediaTypeForText = MediaType.parse(「text/plain」); MediaType mediaTypeForImage = MediaType.parse(「image/*」);

Map params = new HashMap <>(); params.put(「first-parameter」,MultipartBody.create(mediaTypeForText,「first-parameter-value」)); params.put(「second-parameter」,MultipartBody.create(mediaTypeForText,「second-parameter-value」)); (文件[0],MultipartBody.create(mediaTypeForImage,new File(fileUri.getPath())); params.put(「files [1]」,MultipartBody.create(mediaTypeForImage,new File(fileUri。 getPath()));

+0

我已經試過了,沒用! –

+0

雖然改造文檔顯示將「multipart/form-data」設置爲字符串參數和文件的介質類型。 我已經通過爲每個部分設置特定媒體類型再次嘗試了您的建議。 請求已成功發送,但文件未上傳! –

相關問題