Retrofit+RxJava多图以及文字同时上传

学习后写了自己的实现,地址:https://github.com/yanghuiyu39/retrofix_rejava

根据http/1.1 rfc 2616的协议规定,我们的请求方式只有OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE等,那为为何我们还会有multipart/form-data请求之说呢?这里简要说明下。

http协议大家都知道是规定了以ASCII码传输,建立在tcp、ip协议之上的应用层规范,规范内容把http请求分为3个部门:请求方法 URI 协议/版本,请求头,请求正文。所有的方法、实现都是围绕如何运用和组织这三部分来完成的。

也就是说http协议原始方法不支持multipart/form-data请求,那这个请求自然就是由这些原始的方法演变而来的,具体如何演变如下:

1、multipart/form-data的基础方法是post,也就是说是由post方法来组合实现的 
2、multipart/form-data与post方法的不同之处:请求头,请求体。 
3、multipart/form-data的请求头必须包含一个特殊的头信息:Content-Type,且其值也必须规定为multipart/form-data,同时还需要规定一个内容分割符用于分割请求体中的多个post的内容,如文件内容和文本内容自然需要分割开来,不然接收方就无法正常解析和还原这个文件了。具体的头信息如下:

<code class="hljs haskell has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">Content</span>-<span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">Type</span>: multipart/form-<span class="hljs-typedef" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">data</span>; boundary=$<span class="hljs-container" style="box-sizing: border-box;">{<span class="hljs-title" style="box-sizing: border-box;">bound</span>}</span>  </span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

//其中${bound} 是一个占位符,代表我们规定的分割符,可以自己任意规定,但为了避免和正常文本重复了,尽量要使用复杂一点的内容。如:——————–56423498738365

4、multipart/form-data的请求体也是一个字符串,不过和post的请求体不同的是它的构造方式,post是简单的name=value值连接,而multipart/form-data则是添加了分隔符等内容的构造体。具体格式如下:

《Retrofit+RxJava多图以及文字同时上传》

其中${bound}为之前头信息中的分割符,如果头信息中规定为123,那么这里也要为123,;可以很容易看出,这个请求体是多个相同的部分组成的:每一个部分都是以–加分隔符开始的,然后是该部分内容的描述信息,然后一个回车,然后是描述信息的具体内容;如果传送的内容是一个文件的话,那么还会包含文件名信息,以及文件内容的类型。上面的第二个小部分其实是一个文件体的结构,最后会以–分割符–结尾,表示请求体结束。

通过上面分析,可以知道要发送一个multipart/form-data的请求,其实任何支持post请求的工具或语言都可以支持,只是自己要稍微包装一下便可。同样,《自己动手写HTTP框架》里面的HTTP框架也是这么实现的,具体可以看看代码。

下面我们结合具体的接口来分析multipart/form-data的请求。

抓包分析

课程中上传图片相关代码如下图所示:

《Retrofit+RxJava多图以及文字同时上传》

从上面的代码中可以看出,把图片放在了列表中,图片描述放在了request.content中。

通过对该方法运行时的网络请求抓包分析如下:

《Retrofit+RxJava多图以及文字同时上传》

返回结果抓包分析如下:

《Retrofit+RxJava多图以及文字同时上传》

<p style="margin-top:0px; margin-bottom:1.1em; paddi

点赞