Android Retrofit 實現文字(參數)和多張圖片一起上傳

daben 8年前發布 | 50K 次閱讀 Android Retrofit Android開發 移動開發

需求

Retrofit普及后,最近好多人都在問,如何實現Retrofit上傳多文件+文字需求(朋友圈發圖片+文字)

解決方案

google: retrofit upload multiple files

說重點

與其直接說答案,不如我們花點時間說說多文件上傳的原理,這樣,以后就算出了其他的http框架,你也能快速實現。

HTTP協議就不講了吧?反正copy一段過來也不會有人看。我們就直接跳到文件上傳去。想看也可以,傳送門

post form 表單

Android Retrofit 實現文字(參數)和多張圖片一起上傳

 

上圖是不是很常見,在網頁里選一個文件,點擊上傳。上傳到哪里?服務器咯。web和移動端本質上有區別嘛?木有啊,就是一個前端展示的client。那服務器會為移動端創造一套獨立的API嘛?顯然他沒那么傻。

這個文件上傳經常會伴隨著其他fields一起上傳。可以簡單理解為表單上傳。

先來看下,如果沒有文件,也不用json,單獨上傳一些key value怎么做?在Postman里可以這樣模擬。

Android Retrofit 實現文字(參數)和多張圖片一起上傳

 

表單上傳要注意的是

  1. content-type設為application/x-www-form-urlencoded
  2. form表單在streaming時是"weibo=stay4it&wechat=stay4it&qq=104816053"

多文件上傳

實際上,多文件上傳與form表單是一回事,一個key對應一個value。文件上傳就是文件名key對應文件byte[] value,如下圖postman模擬請求

Android Retrofit 實現文字(參數)和多張圖片一起上傳

 

只是如何標記一個key value的開始結束呢?用&分割肯定不夠用啦。那就得用個特殊的boudary來做為分隔符。

另外,這個content-type得為multiple/form-data

好了。科普到此結束。簡單理解HTTP協議以及form表單概念,相信接下來的代碼你就不只是會調用,還能明白為什么。

最原始的上傳方式

以前大家都用HttpUrlConnection,Stay在自己動手寫HTTP框架-19課時詳細講過如何上傳多文件以及進度更新。這里貼下核心代碼:

Android Retrofit 實現文字(參數)和多張圖片一起上傳

 

以上這個UploadUtil,拿到outputstream,分別寫入postContent以及List<FileEntity>,代碼不多,相信大家都能看明白。

抓個包看看

請求數據抓包

Android Retrofit 實現文字(參數)和多張圖片一起上傳

上傳的有兩個form,
一個content-typetext/plain key為data, value為stay4it
一個content-typeimage/png key為file0, value為文件的bytes

服務器如何接收的?(PHP版)

Android Retrofit 實現文字(參數)和多張圖片一起上傳

 

代碼還算好懂,$_FILES就是請求上傳的多文件,只要content-type設置為multiple/form-data,服務器接收是就會將其當成文件處理,將文件接收在$_FILES中,等待處理(存數據庫,存硬盤或轉七牛云等等),$this->data是表單中key為data所對應的valuestay4it。(以后再有服務器er告訴你分兩個API上傳,你就可以這么懟他了: )

返回結果抓包

Android Retrofit 實現文字(參數)和多張圖片一起上傳

好了,原始的方式聊的差不多了,雖然代碼看起來很多,但已經是個util類了,倒不是那么難用。但是我們還是希望在寫代碼時能盡可能少的去關注內部實現啊。什么multiple/form-data,什么boundary。真是很麻煩嘛。

鳥槍換大炮吧

以下Retrofit多文件上傳內容由一葉飄舟大神提供。

Retrofit實現文件和圖片一起上傳

如果對retrofit不是很了解,參考:初識Retrofit

定義接口

根據對Stay自己動手寫HTTP框架-19課時提供的上傳圖片接口的大量抓包和測試總結,接口定義如下:

Android Retrofit 實現文字(參數)和多張圖片一起上傳

這里用到了@Partmap注解,將圖片文件信息放入map中。

準備圖片

在sdcard根目錄存放兩張圖片,分別為test.png和test.jpg(不要是gif圖片啊,服務器不支持)

代碼實現

這里就不貼代碼了,截圖如下(如果看不清,鼠標右鍵在新窗口打開就可以看到原圖了):

Android Retrofit 實現文字(參數)和多張圖片一起上傳

關鍵代碼在于:

Android Retrofit 實現文字(參數)和多張圖片一起上傳

看到這個是不是想起了上面我們提到的關鍵代碼呢?下面再貼出來我們對比下。

Android Retrofit 實現文字(參數)和多張圖片一起上傳

只要將對應的http請求頭信息填寫正確,就能上傳成功。

那么問題又來了,怎么分析和正確拼寫這個請求頭呢?

在文章開頭的時候有個抓包信息:

Content-Disposition: form-data; name="file0"; filename="test.png"

實質上上傳文件Requestbody對應的請求頭就是 name="file0"; filename="test.png",只要拼對了就沒有問題了。

注意:

  1. name="file0"; filename="test.png"這個請求頭是根據有心課堂提供的上傳接口寫的,不適用其他上傳接口,但原理是類似的;
  2. 單張圖片上傳通用的請求頭是:name="file"; filename="test.png"
  3. filename="test.png"這個一般是指(你希望)保存在服務器的文件名字。

舉例說明

比如我們這樣寫請求頭信息,如下代碼所示:

Android Retrofit 實現文字(參數)和多張圖片一起上傳

運行請求抓包請求頭信息如下圖所示:

Android Retrofit 實現文字(參數)和多張圖片一起上傳

出現了name="name="file1"這樣的字段,拼接錯誤(不用加name字段),服務器也毫不留情的返回了錯誤:

Android Retrofit 實現文字(參數)和多張圖片一起上傳

這個問題我當初沒有發現,后來還是請教了Stay才搞明白了。

好了,不知道我講的大家明白了沒有,最后來個成功運行的請求抓包截圖吧:

Android Retrofit 實現文字(參數)和多張圖片一起上傳

關于文字類參數上傳

寫到最后忘了說文字參數了,文字參數相對文件來說容易些。

在接口中,我們有一個文字參數 @Part("data") String des,如果你需要多個,增加就行了。需要注意的是這個參數的名字比如"data",不是前端自定義,而是后臺定義的。

代碼托管地址:https://github.com/stay4it/RetrofitTutorial

 


來自:http://www.jianshu.com/p/3b8b2a0c0f30

 

 本文由用戶 daben 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!