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

背景

在有心课堂《自己动手写HTTP框架》课程中有下列课程:

自拍要发朋友圈如何实现 http://stay4it.com/course/4/learn#lesson/208

通过自己写的HTTP框架实现将图片和文字等内容在一个接口中提交到服务器。无论哪种网络框架,都要遵守HTTP协议。下面我们简单了解下HTTP协议。

HTTP协议

其中HTTP协议版本有两种:HTTP1.0/HTTP1.1 可以这样区别:

  • HTTP1.0对于每个连接都的建立一次连接一次只能传送一个请求和响应,请求就会关闭,HTTP1.0没有Host字段;
  • HTTP1.1在同一个连接中可以传送多个请求和响应,多个请求可以重叠和同时进行,HTTP1.1必须有Host字段。

HTTP请求类型

根据HTTP标准,HTTP请求可以使用多种请求方法。例如:HTTP1.1支持7种请求方法:GET、POST、HEAD、OPTIONS、PUT、DELETE和TARCE。在Internet应用中,最常用的方法是GET和POST。

GET: 请求指定的页面信息,并返回实体主体。

POST: 请求服务器接受所指定的文档作为对所标识的URI的新的从属实体。

HTTP请求格式

当浏览器向Web服务器发出请求时,它向服务器传递了一个数据块,也就是请求信息,HTTP请求信息由3部分组成:

① 请求方法 URI 协议/版本

② 请求头(Request Header)

③ 请求正文

下面是一个HTTP请求的例子:

  • 请求方法URI协议/版本

请求的第一行是“方法URL协议版本”:GET/sample.jsp HTTP/1.1

如上面图片所示,“GET”代表请求方法,“/sample.jsp”表示URI,“HTTP/1.1代表协议和协议的版本。

URL完整地指定了要访问的网络资源,通常只要给出相对于服务器的根目录的相对目录即可,因此总是以“/”开头,最后,协议版本声明了通信过程中使用HTTP的版本。

  • 请求头(Request Header)

请求头包含许多有关的客户端环境和请求正文的有用信息。例如,请求头可以声明浏览器所用的语言,请求正文的长度等。

  • 请求正文

请求头和请求正文之间是一个空行,这个行非常重要,它表示请求头已经结束,接下来的是请求正文。请求正文中可以包含客户提交的查询字符串信息:

username=jinqiao&password=1234

在以上的例子的HTTP请求中,请求的正文只有一行内容。当然,在实际应用中,HTTP请求正文可以包含更多的内容。

HTTP Post请求解析

一个稍微完整的HTTP请求报文:

①请求方法

②为请求对应的URL地址,它和报文头的Host属性组成完整的请求URL,③是协议名称及版本号。

④是HTTP的报文头,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息。

⑤是报文体,它将一个页面表单中的组件值通过param1=value1&param2=value2的键值对形式编码成一个格式化串,它承载多个请求参数的数据。不但报文体可以传递请求参数,请求URL也可以通过类似于“/aremiyi/wonter.html? param1=value1&param2=value2”的方式传递请求参数。

Accept、Cookie 、Referer等属于HTTP请求报文报文头,了解其含义或者更多报文头参考:http://blog.csdn.net/jdsjlzx/article/details/52259312

HTTP multipart/form-data请求分析

说完了Get、Post请求,我们来说说multipart/form-data请求,这也是这篇博客的核心。

根据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的内容,如文件内容和文本内容自然需要分割开来,不然接收方就无法正常解析和还原这个文件了。具体的头信息如下:

Content-Type: multipart/form-data; boundary=${bound}  
  • 1

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

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

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

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

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

抓包分析

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

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

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

返回结果抓包分析如下:

从上图Contents项中可以看到有两个关键字段,分别是data和file0字段。

这两个字段是怎么产生的呢?

通过查看《自己动手写HTTP框架》相关代码,有如下方法:

这个是单张图片上传,紧接着看多张图片上传,代码如下:

通过对上面两段代码的比较,发现主区别在这个地方:

这个地方也是我们使用Retrofit上传的关键点所在,后面我们会再提到。

上面分析了这么多,我们来看看怎么使用retrofit来实现。

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

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

定义接口

在码小白的博客 Retrofit 2.0 超能实践,轻松实现多文件/图片上传 中有下面内容:

图片和字符串同时上报

这种接口应该也是可以的,具体要怎么实现,都要与服务器接口保持一致,所以不能照搬照抄了。

根据对有心课堂提供的上传图片接口的大量抓包和测试总结,接口定义如下:

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

准备图片

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

代码实现

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

关键代码在于:

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

只要将对应的http请求头信息填写正确,就能上传成功。

那么问题又来了,怎么分析和正确拼写这个请求头呢?

在文章开头的时候有个抓包信息:

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

实质上上传文件Requestbody对应的请求头就是 name=”file0”; filename=”test.png”,只要拼对了就没有问题了。

注意:

  1. name=”file0”; filename=”test.png”这个请求头是根据有心课堂提供的上传接口写的,不适用其他上传接口,但原理是类似的;
  2. 单张图片上传通用的请求头是:name=”file”; filename=”test.png”
  3. filename=”test.png”这个一般是指(你希望)保存在服务器的文件名字。

举例说明

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

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

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

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

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

关于文字类参数上传

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

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

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

2016.8.19 凌晨

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

原文地址:https://www.cnblogs.com/skiwnchhw/p/10349641.html

时间: 2024-10-22 23:59:09

Android Retrofit 实现(图文上传)文字(参数)和多张图片一起上传的相关文章

python接口自动化11-post传data参数案例【转载】

前言: 前面登录博客园的是传json参数,有些登录不是传json的,如jenkins的登录,本篇以jenkins登录为案例,传data参数. 一.登录jenkins抓包 1.登录jenkins,输入账号和密码 2.fiddler抓包 3.这个body参数并不是json格式,是key=value格式,也就是前面介绍post请求四种数据类型里面的第二种 二.请求头部 1.上面抓包已经知道body的数据类型了,那么头部里面Content-Type类型也需要填写对应的参数类型 三.实现登录 1.登录代码

python接口自动化11-post传data参数案例

前言: 前面登录博客园的是传json参数,有些登录不是传json的,如jenkins的登录,本篇以jenkins登录为案例,传data参数. 一.登录jenkins抓包 1.登录jenkins,输入账号和密码 2.fiddler抓包 3.这个body参数并不是json格式,是key=value格式,也就是前面介绍post请求四种数据类型里面的第二种 二.请求头部 1.上面抓包已经知道body的数据类型了,那么头部里面Content-Type类型也需要填写对应的参数类型 三.实现登录 1.登录代码

jquery的uploadify插件多文件上传配置参数详解

最近做了个多文件上传,需要限制上传文件类型的例子.以前没做过找了一些资料,下次有用.同时也给大家做参考. uploader: uploadify.swf 文件的相对路径,该swf文件是一个带有文字BROWSE的按钮,点击后淡出打开文件对话框,默认值:uploadify.swf. script: 后台处理程序的相对路径 .默认值:uploadify.php checkScript:用来判断上传选择的文 件在服务器是否存在的后台处理程序的相对路径 fileDataName:设置一个名字,在服务器处理

Android手势识别 Camera 预览界面上显示文字 布局注意事项(merge布局)

通常在Surfaceview作为预览视频帧的载体,有时需在上面显示提示文字.以前我弄的都好好的,今天忽然发现叠加的TextView不管咋弄都出不来文字了,跟Surfaceview一起放在FrameLayout也不行,后来想到merge布局,发现也不行.大爷的,奇了怪了,最后发现了原因,原来是顺序问题.也即无论是在RelativeLayout里还是merge布局里,View是逐个叠加上去的,一层一层铺上去的.如果你先放TextView在最前面,那肯定被后面的全屏Surfaceview覆盖了.用常规

Android中自定义MultipartEntity实现文件上传以及使用Volley库实现文件上传

最近在参加CSDN博客之星,希望大家给投一票,谢谢啦~                       点这里投我一票吧~ 前言 在开发当中,我们常常需要实现文件上传,比较常见的就是图片上传,比如修改个头像什么的.但是这个功能在Android和iOS中都没有默认的实现类,对于Android我们可以使用Apache提供的HttpClient.jar来实现这个功能,其中依赖的类就是Apache的httpmime.jar中的MultipartEntity这个类.我就是要实现一个文件上传功能,但是我还得下载

百度上传工具webuploader,图片上传附加参数

项目中需要上传视频,图片等资源.最先做的是上传图片,开始在网上找了一款野鸡插件,可以实现图片上传预览(无需传到后台).但是最近这个插件出了莫名的问题,不易修复,一怒之下,还是决定找个大点的,靠谱的插件吧.加之上传视频就是用的webuploader,所以上传图片也理所当然选它了. 插件初始化,js引用什么的,官方文档上都写的比较清楚,建议直接去官方api去看 http://fex.baidu.com/webuploader/getting-started.html#图片上传 官方api上值给出了上

Android控件TextProgressBar进度条上显文字

Android系统的进度条控件默认的设计的不是很周全,比如没有包含文字的显示,那么如何在Android进度条控件上显示文字呢? 来自Google内部的代码来了解下,主要使用的addView这样的方法通过覆盖一层Chronometer秒表控件来实现,整个代码如下 : public class TextProgressBar extends RelativeLayout implements OnChronometerTickListener { public static final String

论httpclient上传带参数【commons-httpclient和apache httpclient区别】

需要做一个httpclient上传,然后啪啪啪网上找资料 1.首先以前系统中用到的了commons-httpclient上传,找了资料后一顿乱改,然后测试 PostMethod filePost = new PostMethod(url); filePost.setParameter("system", "vinuxpost"); try { Part part[] = UploadRequestHelper.getPart(request); filePost.s

iOS开发-AFNetworking参数和多文件同时上传【多文件上传】

1. 前言 在项目开发中,我们经常需要上传文件,例如:上传图片,上传各种文件,而有时也需要将参数和多个文件一起上传,不知道大家的项目中遇到了没有,我在最近的项目中,就需要这样的一个功能:同时上传参数.多张图片和音频: 2. 功能实现 在实现此功能之前,需要引入第三方AFNetworking,这是一个非常强大的网络开发工具,这里我就不多说了,下面是我用此工具,封装的一个同时上传参数和多个文件的方法: 2.1 方法名 /** 多文件上传,支持同时上传参数.多个图片.多个音频,[需要将每一个文件转化为