Retrofit 实现文字(参数)和多张图片一起上传

需求

Retrofit普及后,最近好多人都在问,如何实现Retrofit上传多文件+文字需求(朋友圈发图片+文字)

解决方案

google: retrofit upload multiple files

说重点

与其直接说答案,不如我们花点时间说说多文件上传的原理,这样,以后就算出了其他的http框架,你也能快速实现。

HTTP协议就不讲了吧?反正copy一段过来也不会有人看。我们就直接跳到文件上传去。想看也可以,传送门

post form 表单

upload01.png

上图是不是很常见,在网页里选一个文件,点击上传。上传到哪里?服务器咯。web和移动端本质上有区别嘛?木有啊,就是一个前端展示的client。那服务器会为移动端创造一套独立的API嘛?显然他没那么傻。

这个文件上传经常会伴随着其他fields一起上传。可以简单理解为表单上传。

先来看下,如果没有文件,也不用json,单独上传一些key value怎么做?在Postman里可以这样模拟。

upload03.png

表单上传要注意的是

  1. content-type设为application/x-www-form-urlencoded
  2. form表单在streaming时是"weibo=stay4it&wechat=stay4it&qq=104816053"

多文件上传

实际上,多文件上传与form表单是一回事,一个key对应一个value。文件上传就是文件名key对应文件byte[] value,如下图postman模拟请求

upload04.png

只是如何标记一个key value的开始结束呢?用&分割肯定不够用啦。那就得用个特殊的boudary来做为分隔符。

另外,这个content-type得为multiple/form-data

好了。科普到此结束。简单理解HTTP协议以及form表单概念,相信接下来的代码你就不只是会调用,还能明白为什么。

最原始的上传方式

以前大家都用HttpUrlConnection,Stay在自己动手写HTTP框架-19课时详细讲过如何上传多文件以及进度更新。这里贴下核心代码:

upload05.png

以上这个UploadUtil,拿到outputstream,分别写入postContent以及List<FileEntity>,代码不多,相信大家都能看明白。

抓个包看看

请求数据抓包

upload06.png

上传的有两个form,
一个content-typetext/plain key为data, value为stay4it
一个content-typeimage/png key为file0, value为文件的bytes

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

upload08.png

代码还算好懂,$_FILES就是请求上传的多文件,只要content-type设置为multiple/form-data,服务器接收是就会将其当成文件处理,将文件接收在$_FILES中,等待处理(存数据库,存硬盘或转七牛云等等),$this->data是表单中key为data所对应的valuestay4it。(以后再有服务器er告诉你分两个API上传,你就可以这么怼他了: )

返回结果抓包

upload07.png

好了,原始的方式聊的差不多了,虽然代码看起来很多,但已经是个util类了,倒不是那么难用。但是我们还是希望在写代码时能尽可能少的去关注内部实现啊。什么multiple/form-data,什么boundary。真是很麻烦嘛。

鸟枪换大炮吧

以下Retrofit多文件上传内容由一叶飘舟大神提供。

Retrofit实现文件和图片一起上传

如果对retrofit不是很了解,参考:初识Retrofit

定义接口

根据对Stay自己动手写HTTP框架-19课时提供的上传图片接口的大量抓包和测试总结,接口定义如下:

upload09.png

这里用到了@Partmap注解,将图片文件信息放入map中。

准备图片

在sdcard根目录存放两张图片,分别为test.png和test.jpg(不要是gif图片啊,服务器不支持)

代码实现

这里就不贴代码了,截图如下(如果看不清,鼠标右键在新窗口打开就可以看到原图了):

upload10.png

关键代码在于:

upload11.png

看到这个是不是想起了上面我们提到的关键代码呢?下面再贴出来我们对比下。

upload12.png

只要将对应的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"这个一般是指(你希望)保存在服务器的文件名字。

举例说明

比如我们这样写请求头信息,如下代码所示:

upload13.png

运行请求抓包请求头信息如下图所示:

upload14.png

出现了name="name="file1"这样的字段,拼接错误(不用加name字段),服务器也毫不留情的返回了错误:

upload15.png

这个问题我当初没有发现,后来还是请教了Stay才搞明白了。

好了,不知道我讲的大家明白了没有,最后来个成功运行的请求抓包截图吧:

upload16.png

关于文字类参数上传

写到最后忘了说文字参数了,文字参数相对文件来说容易些。

在接口中,我们有一个文字参数 @Part("data") String des,如果你需要多个,增加就行了。需要注意的是这个参数的名字比如"data",不是前端自定义,而是后台定义的。

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

2016.8.19 凌晨

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,799评论 25 707
  • 整体Retrofit内容如下: 1、Retrofit解析1之前哨站——理解RESTful2、Retrofit解析2...
    隔壁老李头阅读 15,060评论 4 39
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 分享微博博主思想聚焦的《西游2》影评 《我可能看了个假西游。很多人说...》 思想聚焦 ...
    胡小安阅读 270评论 2 1
  • 夏日的一个清晨,天气格外晴朗,朝阳一如既往地爬上了地平线,叫醒了这座沉睡的城市。 他看了看手上的表,已经不早了,...
    峻铭阅读 527评论 0 0