Multipart/form-data POST文件上传详解

理论

简单的HTTP POST

大家通过HTTP向服务器发送POST请求提交数据,都是通过form表单提交的,代码如下:

<form method="post"action="http://w.sohu.com" >

<inputtype="text" name="txt1">

<inputtype="text" name="txt2">

</form>

提交时会向服务器端发出这样的数据(已经去除部分不相关的头信息),数据如下:

POST / HTTP/1.1

Content-Type:application/x-www-form-urlencoded

Accept-Encoding: gzip, deflate

Host: w.sohu.com

Content-Length: 21

Connection: Keep-Alive

Cache-Control: no-cache

txt1=hello&txt2=world

对于普通的HTML Form POST请求,它会在头信息里使用Content-Length注明内容长度。头信息每行一条,空行之后便是Body,即“内容”(entity)。它的Content-Type是application/x-www-form-urlencoded,这意味着消息内容会经过URL编码,就像在GET请 求时URL里的QueryString那样。txt1=hello&txt2=world

POST上传文件

最早的HTTP POST是不支持文件上传的,给编程开发带来很多问题。但是在1995年,ietf出台了rfc1867,也就是《RFC 1867 -Form-based File Upload in HTML》,用以支持文件上传。所以Content-Type的类型扩充了multipart/form-data用以支持向服务器发送二进制数据。因此发送post请求时候,表单<form>属性enctype共有二个值可选,这个属性管理的是表单的MIME编码:

①application/x-www-form-urlencoded(默认值)
 ②multipart/form-data
其实form表单在你不写enctype属性时,也默认为其添加了enctype属性值,默认值是enctype="application/x- www-form-urlencoded".

通过form表单提交文件操作如下:

<form method="post"action="http://w.sohu.com/t2/upload.do" enctype=”multipart/form-data”>

<inputtype="text" name="desc">

<inputtype="file" name="pic">

</form>

浏览器将会发送以下数据:

POST /t2/upload.do HTTP/1.1

User-Agent: SOHUWapRebot

Accept-Language: zh-cn,zh;q=0.5

Accept-Charset: GBK,utf-8;q=0.7,*;q=0.7

Connection: keep-alive

Content-Length: 60408

Content-Type:multipart/form-data; boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Host: w.sohu.com

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Content-Disposition: form-data;name="desc"

Content-Type: text/plain; charset=UTF-8

Content-Transfer-Encoding: 8bit

[......][......][......][......]...........................

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Content-Disposition: form-data;name="pic"; filename="photo.jpg"

Content-Type: application/octet-stream

Content-Transfer-Encoding: binary

[图片二进制数据]

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--

我们来分析下数据,第一个空行之前自然还是HTTP header,之后则是Entity,而此时的Entity也比之前要复杂一些。根据RFC 1867定义,我们需要选择一段数据作为“分割边界”( boundary属性),这个“边界数据”不能在内容其他地方出现,一般来说使用一段从概率上说“几乎不可能”的数据即可。 不同浏览器的实现不同,例如火狐某次post的  boundary=---------------------------32404670520626 , opera为boundary=----------E4SgDZXhJMgNE8jpwNdOAX ,每次post浏览器都会生成一个随机的30-40位长度的随机字符串,浏览器一般不会遍历这次post的所有数据找到一个不可能出现在数据中的字符串,这样代价太大了。一般都是随机生成,如果你遇见boundary值和post的内容一样,那样的话这次上传肯定失败,不过我建议你去买彩票,你太幸运了。Rfc1867这样说明{A boundary is selected that does not occur in any of the data. (This selection is sometimes done probabilisticly.)}。

选择了这个边界之后,浏览器便把它放在Content-Type 里面传递给服务器,服务器根据此边界解析数据。下面的数据便根据boundary划分段,每一段便是一项数据。(每个field被分成小部分,而且包含一个value是"form-data"的"Content-Disposition"的头部;一个"name"属性对应field的ID,等等,文件的话包括一个filename)

  • IE和Chrome在filename的选择策略上有所不同,前者是文件的完整路径,而后者则仅仅是文件名。
  • 数据内容以两条横线结尾,并同样以一个换行结束。在网络协议中一般都以连续的CR、LF(即\r、\n,或0x0D、Ox0A)字符作为换行,这与Windows的标准一致。如果您使用其他操作系统,则需要考虑它们的换行符。

另外Content-length 指的是所用数据的长度。

实现

httpClient4如何实现

httpClient4使用http-mime.jar包的MultipartEntity实现,代码如下(为了简洁,处理了异常处理代码):

HttpPost httpPost = newHttpPost(url);

Log.debug("post url:"+url);

httpPost.setHeader("User-Agent","SOHUWapRebot");

httpPost.setHeader("Accept-Language","zh-cn,zh;q=0.5");

httpPost.setHeader("Accept-Charset","GBK,utf-8;q=0.7,*;q=0.7");

httpPost.setHeader("Connection","keep-alive");

MultipartEntity mutiEntity = newMultipartEntity();

File file = new File("d:/photo.jpg");

mutiEntity.addPart("desc",new StringBody("美丽的西双版纳", Charset.forName("utf-8")));

mutiEntity.addPart("pic", newFileBody(file));

httpPost.setEntity(mutiEntity);

HttpResponse  httpResponse = httpClient.execute(httpPost);

HttpEntity httpEntity =  httpResponse.getEntity();

String content = EntityUtils.toString(httpEntity);

参考:

Rfc1867:http://www.ietf.org/rfc/rfc1867

Rfc1867:http://www.vivtek.com/rfc1867.html

Multipart/form-data POST文件上传详解相关推荐

  1. Struts2之struts2文件上传详解

    一.学习案例:通过在uploadfile.jsp页面填写完表单,提交后跳转到success.jsp页面,然后验证upload包下上传文件是否成功. 二.案例分析:struts2文件上传并不是表面上看的 ...

  2. JAVA文件上传详解(附源码)

    文章目录 JAVA文件上传详解(附源码) 1.准备工作 2.使用类介绍 FileItem类 ServletFileUpload类 3.代码编写 JAVA文件上传详解(附源码) 在web应用中,文件上传 ...

  3. php文件上传详解,PHP文件上传实例详解!!!

    这篇文章主要介绍了PHP文件上传实例代码,需要的朋友可以参考下 首先来看下上传部分的表单代码: 文件:  这里有几个要注意的地方,首先看这句 ,这里我们采用POST方法,个别浏览器还支持PUT方法,当 ...

  4. python爬虫:Multipart/form-data POST文件上传详解

    简单的HTTP POST 大家通过HTTP向服务器发送POST请求提交数据,都是通过form表单提交的,代码如下: <form method="post"action=&qu ...

  5. Retrofit2 multpart多文件上传详解

    原文出处:http://www.chenkaihua.com/2016/04/02/retrofit2-upload-multipart-files.html Retrofit2是目前很流行的andr ...

  6. java web文件上传详解_java web图片上传和文件上传实例详解

    java web图片上传和文件上传 图片上传和文件上传本质上是一样的,图片本身也是文件.文件上传就是将图片上传到服务器,方式虽然有很多,但底层的实现都是文件的读写操作. 注意事项 1.form表单一定 ...

  7. Struts2之Servlet文件上传详解

    声明:此次讲解文件上传使用的FileUpload组件和IO组件,都是Apache官网最新版,FileUpload版本号:commons-fileupload-1.3.1-bin.zip,IO版本号:c ...

  8. elment-ui文件上传详解

    文件上传总有各种问题,算是给自己一个总结吧 HTML <el-form-item prop="" class="form-item"><tem ...

  9. WEUI文件上传详解

    本文通过我个人设计的系统为案例来教会读者使用weui的uploader,先来看看效果图: 图片上传框 PC端 移动端 首先,微信的官方文档不会一步一步教会你怎么用,但是在其中能发现很多使用的细节,推荐 ...

最新文章

  1. WebClient UI删除搜索条件的后台处理,以及max hit的处理逻辑
  2. linux最基础的几个指令
  3. 初识类的构造方法 c# 1214
  4. windows环境设置mysql自动备份(测试成功)
  5. Redis系列(七)--Sentinel哨兵模式
  6. osgearth介绍
  7. 【BZOJ】【2626】JZPFAR
  8. 【CF Contest-1228 E】Another Filling the Grid【容斥】
  9. C语言99乘法表代码案例
  10. (1.4.10)SXF笔试题汇总
  11. winrar 5.80正式版全球发布
  12. AI魔幻行为大赏:细数机器视觉的9大应用场景
  13. 计算机网络 DNS服务介绍
  14. 【开源分享】多端发布的单商户商城系统
  15. Transformer解读之:Transformer 中的 Attention 机制
  16. VM虚拟机启动U盘内镜像
  17. 学习笔记——利用CC++语言计算二重积分
  18. 基于maxwell的反电动势波形导出处理
  19. centos升级gdb支持pretty-printer
  20. excel怎么一个格子斜分_『在Excel中,把一个格子用线分成三个怎么弄啊』一个单元格怎么斜分两个...

热门文章

  1. spring MVC 工作原理
  2. IOS 自定义NIB视图
  3. 扩展的母函数(可以做减法的母函数)(当然只要你愿意也可以做乘除!)
  4. Linux 卷管理详解[ pv vg lv] —— 之三
  5. PaaS云计算平台服务商大集合
  6. CodeForces - 1316E Team Building(状压dp)
  7. boolean类型_JS核心理论之《数据类型、类型转换、深浅拷贝与参数传递》
  8. dataframe 加一行_虎牙公会是干嘛的?虎牙直播有必要加公会吗?
  9. 天锋w2019_不知道为什么那么多人喜欢三星W2019,直到入手这款天锋W2019手机
  10. C++ 操作64位系统,默认读取Wow6432Node子键的解决方法。